SSL Issue with Android
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";
}
}
Don Quixote
Updated on June 11, 2022Comments
-
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.
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 almost 12 yearsInitially 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 almost 12 yearsThe 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 almost 12 yearsHi 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 almost 12 yearsThat'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 almost 12 yearsFor 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 almost 12 yearsBy using this
TrustManager
, you're opening yourself to MITM attacks. -
user802467 over 9 yearsMy 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 over 9 years01-29 15:58:00.073 5486 5525 W chromium_net: external/chromium/net/http/http_stream_factory_impl_job.cc:865: [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:792: [0129/155800:ERROR:ssl_client_socket_openssl.cc(792)] handshake failed; returned 0, SSL error code 5, net_error -107
-
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