square / okhttp

Square’s meticulous HTTP client for the JVM, Android, and GraalVM.
https://square.github.io/okhttp/
Apache License 2.0
45.84k stars 9.16k forks source link

SSLHandshakeException while connecting to NASA's APOD servers on Pre-5.0 Android Devices #3098

Closed JeffreyCA closed 7 years ago

JeffreyCA commented 7 years ago

OkHttp Version: 2.7.5

Relevant code:

OkHttpClient client = new OkHttpClient();
final String src = "https://apod.nasa.gov/apod/astropix.html";
final Request.Builder request = new Request.Builder().get().url(src);

client.newCall(request.build()).enqueue(new Callback() {
    @Override
    public void onFailure(Request request, IOException e) {

    }

    @Override
    public void onResponse(Response response) throws IOException {

    }
});

Error Message:

javax.net.ssl.SSLHandshakeException: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb94675e0: 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:741 0x98977990:0x00000000)
  at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:448)
  at com.squareup.okhttp.Connection.upgradeToTls(Connection.java:241)
  at com.squareup.okhttp.Connection.connect(Connection.java:158)
  at com.squareup.okhttp.Connection.connectAndSetOwner(Connection.java:174)
  at com.squareup.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:120)
  at com.squareup.okhttp.internal.http.RouteSelector.next(RouteSelector.java:131)
  at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:312)
  at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:235)
  at com.squareup.okhttp.Call.getResponse(Call.java:262)
  at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:219)
  at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:192)
  at com.squareup.okhttp.Call.access$100(Call.java:34)
  at com.squareup.okhttp.Call$AsyncCall.execute(Call.java:156)
  at com.squareup.okhttp.internal.NamedRunnable.run(NamedRunnable.java:33)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
  at java.lang.Thread.run(Thread.java:841)
  Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0xb94675e0: 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:741 0x98977990:0x00000000)
     at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:405)
        ... 16 more

SSLLabs Analysis for the apod.nasa.gov domain shows Server sent fatal alert: handshake_failure for all pre-Lollipop devices (4.4.2 is an exception, but I tested in an emulator and I still got that error) On post-Lollipop devices, the cipher is: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256. Compare to the SSLLabs Analysis of NASA's other domains: there are no handshake errors.

Is this an issue on the provider's side? Is there a solution to successfully connect to the server https://apod.nasa.gov/apod/astropix.html on those older Android devices?

I've tried countless posted solutions such as using custom SocketFactory, using Google Play Services dynamic security provider, unfortunately none worked for me for that specific server.

I don't know much about HTTPS & TLS stuff. I would really appreciate some help. Thank you.

swankjesse commented 7 years ago

Ick. You’ll need to customize the cipher suite – which is difficult – and maybe also the trusted root certificate. Here’s a big ugly sample.

https://gist.github.com/swankjesse/db5619904ea9c3352a9cb18ae903cc25

JeffreyCA commented 7 years ago

Thank you for your help, really appreciate it. I tried your example and implemented it in an Android activity. On 4.4.2, I get the following message:

java.lang.IllegalArgumentException: cipherSuite TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 is not supported.

I don't think the server accepts any of the cipher suites listed here that are compatible with pre-API 20 devices. The devices do not support TLS 1.2, and the server only deals with TLS 1.2.

The server allows these ciphers:

CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
CipherSuite.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA

All of them except for the last one result in java.lang.IllegalArgumentException: cipherSuite is not supported. The last one results in a handshake error.

JeffreyCA commented 7 years ago

I tried this suggestion as well, but still got that error.

swankjesse commented 7 years ago

Try this? https://developer.android.com/training/articles/security-gms-provider.html

JeffreyCA commented 7 years ago

Thank you, it solved it for me! I followed the stuff under Patching Asynchronously, and put the OkHttp request in the onProviderInstalled method, and now the device supports the TLS 1.2 ciphers. I didn't even need to use the NasaClient code. The only requirement was that the device needed an up-to-date version of Google Play Services installed.

vindhyapratap commented 7 years ago

Hey Jeffrey, What if device don't have play services installed and cannot install it. I want to use it in lower version without having play service. Any suggestion. Thanks in advance.

JeffreyCA commented 7 years ago

I would try the suggestion given here or here. There are several other issues opened by others regarding this, maybe have a look at them?