SSL Issue with Android

15,724

Solution 1

How are you accessing this site? Through the Android browser? WebView? Or HttpClient/HTTPSURLConnection? It seems it only responds to SSL3, you have to force your client to use it.

Solution 2

I found the solution (thank you Nikolay for pointing me in the right direction).

The problem was two-fold... one, it was returning a site certificate that Android didn't like, and two, it had only SSLv3 (and not TLS) enabled.

Here was my solution. First I had to create a custom socket factory class:

public class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("SSLv3");

public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
    super(truststore);

    TrustManager tm = new X509TrustManager() {
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {}
        public X509Certificate[] getAcceptedIssuers() {
            return null;
        }
    };

    sslContext.init(null, new TrustManager[] { tm }, null);
}

@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
    SSLSocket S = (SSLSocket) sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
    S.setEnabledProtocols(new String[] {"SSLv3"});
    return S;
}

@Override
public Socket createSocket() throws IOException {
    SSLSocket S = (SSLSocket) sslContext.getSocketFactory().createSocket();
    S.setEnabledProtocols(new String[] {"SSLv3"});
    return S;
}

}

Second, I had this custom HttpClient defined in my code:

public HttpClient getNewHttpClient() {
    try {
        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        trustStore.load(null, null);

        MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
        sf.setHostnameVerifier(MySSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

        SchemeRegistry registry = new SchemeRegistry();
        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        registry.register(new Scheme("https", sf, 443));

        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

        return new DefaultHttpClient(ccm, params);
    } catch (Exception e) {
        return new DefaultHttpClient();
    }
}

Third, I called the custom HttpClient and parsed the results:

public String test(String URIString) {
    HttpClient httpClient = getNewHttpClient();
    String result = "";
    URI uri;
    try {
        uri = new URI(URIString);
    } catch (URISyntaxException e1) {
        return "ERROR";
    }
    HttpHost host = new HttpHost(uri.getHost(), 443, uri.getScheme());
    HttpPost httppost = new HttpPost(uri.getPath());
    try {
        HttpResponse response = httpClient.execute(host, httppost);
        BufferedReader reader = new BufferedReader(
                new InputStreamReader(
                    response.getEntity().getContent()
                )
            );
            String line = null;
            while ((line = reader.readLine()) != null){
              result += line + "\n";
            }

            return result;
    } catch (ClientProtocolException e) {
        return "ERROR";
    } catch (IOException e) {
        return "ERROR";
    }
}
Share:
15,724
Don Quixote
Author by

Don Quixote

Updated on June 11, 2022

Comments

  • Don Quixote
    Don Quixote almost 2 years

    I have a very specific SSL issue on my Android. If I try to visit a particular website via code, I get the following error:

    SSL handshake failure: Failure in SSL library, usually a protocol error
    error:140773F2:SSL routines:SSL23_GET_SERVER_HELLO: sslv3 alert unexpected message (external/openssl/ssl/s23_cInt.c:500 0xaf076228:0x00000000)
    

    I get this regardless of the build... I've tried it on API levels 1.5, 1.6, 2.2, and 4.0 and gotten the same result each time.

    After some troubleshooting I tried to visit the website through a browser and I got the following error:

    Data connectivity problem
    A secure connection could not be established.
    

    Here's the thing, though... the website opens just fine on Windows browsers (tested on Firefox, IE, and Chrome). It also opens just fine on iOS devices which uses the same webkit as the Android, which is odd. The website also works without problems on the Opera Mini browser.

    Here's the website.

    I've tried workarounds by adding the client certificate to the keystore and by ignoring invalid client certificates, with no results. However it appears that the certificate itself is not the issue.

    I'm at an impasse. Can anybody provide any guidance on how I can get this to work?

  • Don Quixote
    Don Quixote almost 12 years
    Initially I tried to access it through HttpClient. After trying several things to get it to work (disabling SSL cert verification, adding the cert to my local keystore, etc.) I determined that the problem wasn't with the certificate itself. I then tried accessing it through a browser but it wouldn't work there either. I haven't tried a WebView because I'm assuming that if the browser can't connect, the WebView can't either. I went back and accepted some answers. The reason for the low acceptance is because most of the answers didn't solve my problems.
  • Nikolay Elenkov
    Nikolay Elenkov almost 12 years
    The problem is that your server only responds to a single SSL version, SSL v3. If using HttpClient you need to create your own SocketFactory and set the enabled protocol version manually. Something similar is described here: developer.android.com/reference/javax/net/ssl/…
  • Don Quixote
    Don Quixote almost 12 years
    Hi Nikolay, after some research I've found exactly what you described. The server does NOT support TLS, which is what the app is trying to handshake with. I'm researching now how to force SSLv3, but I'm not having much luck (this is slightly more advanced than my limited Java experience is used to). Do you think you could provide a very basic code snippet for me?
  • Nikolay Elenkov
    Nikolay Elenkov almost 12 years
    That's about right, but your TrustManager will trust any and all certificates which is not a good idea. Why didn't Android 'like' the server certificate? If it is because it was issued by an untrusted CA, you can easily create a trust store with it, and have your SocketFactory use it.
  • Don Quixote
    Don Quixote almost 12 years
    For right now it's fine... I was unable to progress at all in development because I couldn't authenticate with the web server, and 100% of the app involves communication with the server. Later I'll come back and deal with creating a custom trust store but for now I'm happy just to have working code. It keeps the bosses and clients off my back. ;-)
  • Bruno
    Bruno almost 12 years
    By using this TrustManager, you're opening yourself to MITM attacks.
  • user802467
    user802467 over 9 years
    My server is set to accept only TLS 1.1 and above. setEnabledProtocols function in SSLSocket works for HttpsUrlConnection and custom HttpClient. How about setting the SSL protocol for WebView client? Webview client throws onReceivedError callback with description "Failed to perform SSL handshake".
  • user802467
    user802467 over 9 years
    01-29 15:58:00.073 5486 5525 W chromium_net: external/chromium/net/http/http_stream_factory_impl_job.cc:8‌​65: [0129/155800:WARNING:http_stream_factory_impl_job.cc(865)] Falling back to SSLv3 because host is TLS intolerant: 10.209.126.125:443 01-29 15:58:00.083 5486 5525 E chromium_net: external/chromium/net/socket/ssl_client_socket_openssl.cc:79‌​2: [0129/155800:ERROR:ssl_client_socket_openssl.cc(792)] handshake failed; returned 0, SSL error code 5, net_error -107
  • KK_07k11A0585
    KK_07k11A0585 over 8 years
    @NikolayElenkov I am facing the same issue as above and In my case I am trying to access the website from Android Webview. How can I disable the SSLv3 protocol or set the protocol version manually in Webview ? Please let me know