Code works on my Genymotion Android 4.4.4 emulator but not on the device i'm using (4.4.2).
I've tried lots of "trust all certificate" workarounds but to no avail (I don't think this is the issue anyway, as the certificate is AOK).
I think I have identified the cipher (using a wireshark trace from my desktop); TLS 0x00 0x1E which appears to be somewhat rare?
Any idea how to fix?
Here's my code
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); StrictMode.setThreadPolicy(policy); CloseableHttpClient client = HttpClientBuilder.create().setSSLSocketFactory(sslsf).build(); String baseURL = "https://mysite.co.uk/api/"; HttpGetHC4 request = new HttpGetHC4(baseURL + "/authenticate?user=abcd&password=1234"); CloseableHttpResponse response = client.execute(request);
And error;
javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x6abff398: Failure in SSL library, usually a protocol error error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:744 0x684dfce0:0x00000000) at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:449) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:340) at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:281) at org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:124) at org.apache.http.impl.conn.BasicHttpClientConnectionManager.connect(BasicHttpClientConnectionManager.java:322) at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:373) at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:225) at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:195) at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:86) at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:108) at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:178) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82) at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106) at com.example.lee.printticket.Main$OrderAsyncTask.onPostExecute(Main.java:239) at com.example.lee.printticket.Main$OrderAsyncTask.onPostExecute(Main.java:189) at android.os.AsyncTask.finish(AsyncTask.java:632) at android.os.AsyncTask.access$600(AsyncTask.java:177) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5017) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) at dalvik.system.NativeStart.main(Native Method) Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x6abff398: Failure in SSL library, usually a protocol error error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:744 0x684dfce0:0x00000000) at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method) at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:406) ... 25 more
EDIT
Trying using a different technique/library;
RequestQueue queue = Volley.newRequestQueue(this); String url ="https://mysite.co.uk/api/authenticate?user=abcd&password=1234"; // Request a string response from the provided URL. StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override public void onResponse(String response) { // Display the first 500 characters of the response string. Log.d("response: ", response); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.d("response: ", error.toString()); } }); // Add the request to the RequestQueue. queue.add(stringRequest);
Returns;
D/response:: com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x6ad51be0: Failure in SSL library, usually a protocol error D/response:: error:140740B5:SSL routines:SSL23_CLIENT_HELLO:no ciphers available (external/openssl/ssl/s23_clnt.c:486 0x684dfce0:0x00000000)
Or with the NoSSLv3SocketFactory hack from Javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: Failure in SSL library, usually a protocol error;
HttpStack stack = new HurlStack(null, new NoSSLv3SocketFactory()); RequestQueue queue = Volley.newRequestQueue(this, stack);
Returns;
D/response:: com.android.volley.NoConnectionError: javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x6ae51d30: Failure in SSL library, usually a protocol error D/response:: error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:744 0x684dfce0:0x00000000)
SSL Handshake Failed is an error message that occurs when the client or server wasn't able to establish a secure connection. This might occur if: The client is using the wrong date or time. The client is a browser and its specific configuration is causing the error.
javax.net.ssl.SSLProtocolException. Reports an error in the operation of the SSL protocol. Normally this indicates a flaw in one of the protocol implementations.
Android uses different protocols for network operations.
Default configuration for different Android versions.
I found solution for OkHttpClient.
Protocol Supported (API Levels) Enabled by default (API Levels) SSLv3 1–25 1–22 TLSv1 1+ 1+ TLSv1.1 16+ 20+ TLSv1.2 16+ 20+
So we have to change Protocol for connection in Android VERSION >= 16 & VERSION < 22.
Create java file Tls12SocketFactory.java
/** * Enables TLS v1.2 when creating SSLSockets. * <p/> * For some reason, android supports TLS v1.2 from API 16, but enables it by * default only from API 20. * @link https://developer.android.com/reference/javax/net/ssl/SSLSocket.html * @see SSLSocketFactory */ public class Tls12SocketFactory extends SSLSocketFactory { private static final String[] TLS_V12_ONLY = {"TLSv1.2"}; final SSLSocketFactory delegate; public Tls12SocketFactory(SSLSocketFactory base) { this.delegate = base; } @Override public String[] getDefaultCipherSuites() { return delegate.getDefaultCipherSuites(); } @Override public String[] getSupportedCipherSuites() { return delegate.getSupportedCipherSuites(); } @Override public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { return patch(delegate.createSocket(s, host, port, autoClose)); } @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { return patch(delegate.createSocket(host, port)); } @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException { return patch(delegate.createSocket(host, port, localHost, localPort)); } @Override public Socket createSocket(InetAddress host, int port) throws IOException { return patch(delegate.createSocket(host, port)); } @Override public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { return patch(delegate.createSocket(address, port, localAddress, localPort)); } private Socket patch(Socket s) { if (s instanceof SSLSocket) { ((SSLSocket) s).setEnabledProtocols(TLS_V12_ONLY); } return s; } }
Put this method some where in your code.
public static OkHttpClient.Builder enableTls12OnPreLollipop(OkHttpClient.Builder client) { if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT < 22) { try { SSLContext sc = SSLContext.getInstance("TLSv1.2"); sc.init(null, null, null); client.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory())); ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS) .tlsVersions(TlsVersion.TLS_1_2).build(); List<ConnectionSpec> specs = new ArrayList<>(); specs.add(cs); specs.add(ConnectionSpec.COMPATIBLE_TLS); specs.add(ConnectionSpec.CLEARTEXT); client.connectionSpecs(specs); } catch (Exception exc) { Log.e("OkHttpTLSCompat", "Error while setting TLS 1.2", exc); } } return client; } public OkHttpClient getNewHttpClient() { OkHttpClient.Builder client = new OkHttpClient.Builder().followRedirects(true).followSslRedirects(true) .retryOnConnectionFailure(true).cache(null).connectTimeout(5, TimeUnit.SECONDS) .writeTimeout(5, TimeUnit.SECONDS).readTimeout(5, TimeUnit.SECONDS); return enableTls12OnPreLollipop(client).build(); }
Create OkHttp instance like below :
private OkHttpClient getNewHttpClient() { OkHttpClient.Builder client = new OkHttpClient.Builder() .followRedirects(true) .followSslRedirects(true) .retryOnConnectionFailure(true) .cache(null) .connectTimeout(5, TimeUnit.SECONDS) .writeTimeout(5, TimeUnit.SECONDS) .readTimeout(5, TimeUnit.SECONDS); return enableTls12OnPreLollipop(client).build(); }
Use client object like this:
OkHttpClient client = getNewHttpClient(); Request.Builder requestBuilder = new Request.Builder(); URL url = new URL("YOUR_URL_LINK"); Request request = requestBuilder.url(url).build(); Call call = client.newCall(request); Response response = call.execute();
THANKS
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With