Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CloudFront SSL handshake errors #430

Closed
blacha opened this issue Mar 31, 2016 · 8 comments
Closed

CloudFront SSL handshake errors #430

blacha opened this issue Mar 31, 2016 · 8 comments

Comments

@blacha
Copy link

blacha commented Mar 31, 2016

When connecting to a CloudFront proxied parse-server, on Android 5.0/5.1 the SSL connections will error while attempting to handshake.

I/System.out( 4327): SSLProtocolException:SSL handshake aborted: ssl=0x7fa18fa100: Failure in SSL library, usually a protocol error
I/System.out( 4327): error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure (external/openssl/ssl/s23_clnt.c:770 0x7f9fa59df0:0x00000000)

I have tracked this down to using SSLCertificateSocketFactory.getDefault in : https://github.com/ParsePlatform/Parse-SDK-Android/blob/master/Parse/src/main/java/com/parse/ParseURLConnectionHttpClient.java#L41

I have also tried using okHttp but the same problem exists with okHttp 2.7.5 until this line is removed: https://github.com/ParsePlatform/Parse-SDK-Android/blob/master/Parse/src/main/java/com/parse/ParseOkHttpClient.java#L60

On newer versions of android (6+) this error does not seem to happen.

What repercussions would we face if we stop overriding the SSL socket factory?

Simple test case to reproduce
    OkHttpClient okHttpClient = new OkHttpClient();
    boolean failRequest = true;
    if (failRequest) {
        okHttpClient.setSslSocketFactory(SSLCertificateSocketFactory.getDefault(10000, new SSLSessionCache(new File("/sdcard/cache"))));
    }

    Request r = new Request.Builder()
            .url("https://test.sni.velox.ch/")
            .build();
    Response response = okHttpClient.newCall(r).execute();
Example stacktraces:
# CloudFront SSL Exception
  Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x7fa1998880: 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:770 0x7f9fa59df0:0x00000000)
       at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
       at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:323)
        ... 26 more

# SNI SSL Exception
javax.net.ssl.SSLPeerUnverifiedException: Cannot verify hostname: test.sni.velox.ch
   at android.net.SSLCertificateSocketFactory.verifyHostname(SSLCertificateSocketFactory.java:203)
   at android.net.SSLCertificateSocketFactory.createSocket(SSLCertificateSocketFactory.java:441)
   at com.squareup.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:181)
   at com.squareup.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:149)
   at com.squareup.okhttp.internal.io.RealConnection.connect(RealConnection.java:112)
   at com.squareup.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:184)
   at com.squareup.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
   at com.squareup.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
   at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
   at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
@totrit
Copy link

totrit commented Apr 2, 2016

The direct reason for this is because the handshake message from client does not contain the "Server Name Indication" extention (could be observed through tcpdump). And the root cause for this is the SSLCertificateSocketFactory will immiadeately call handshake before SNI setting (which is necessary for handshake) is done:

// link: https://android.googlesource.com/platform/external/okhttp/+/android-5.1.1_r36/okhttp/src/main/java/com/squareup/okhttp/Connection.java#166
private void upgradeToTls(TunnelRequest tunnelRequest) throws IOException {
    Platform platform = Platform.get();
    ... ...
    // The 'route.address.sslSocketFactory' is actually a 'SSLCertificateSocketFactory'
    socket = route.address.sslSocketFactory
        .createSocket(socket, route.address.uriHost, route.address.uriPort, true /* autoClose */);
    SSLSocket sslSocket = (SSLSocket) socket;
    if (route.modernTls) {
      // This line should be executed before any handshake
      platform.enableTlsExtensions(sslSocket, route.address.uriHost);
    }
    ... ...
    // Here is the handshake
    sslSocket.startHandshake();
}

// link: https://android.googlesource.com/platform/frameworks/base/+/android-5.0.0_r1/core/java/android/net/SSLCertificateSocketFactory.java#522
public Socket createSocket(String host, int port) throws IOException {
        OpenSSLSocketImpl s = (OpenSSLSocketImpl) getDelegate().createSocket(host, port);
        s.setNpnProtocols(mNpnProtocols);
        s.setAlpnProtocols(mAlpnProtocols);
        s.setHandshakeTimeout(mHandshakeTimeoutMillis);
        s.setChannelIdPrivateKey(mChannelIdPrivateKey);
        if (mSecure) {
           // This function internally will call the 'handshake'
            verifyHostname(s, host);
        }
        return s;
    }

On the other hand, if the default factory is not set to be SSLCertificateSocketFactory, the factory will eventually be org/conscrypt/OpenSSLSocketFactoryImpl, which is quite modest and it will not do the too-early-handshake.

The reason why Android6+ does not have this problem is because SNI is enabled by default.

I'm not sure why people are using SSLCertificateSocketFactory, maybe because they can set handshake-timeout through that, because I haven't found any API through which the timeout could be set.

totrit added a commit to totrit/platform_frameworks_base that referenced this issue Apr 4, 2016
Doing handshake without proper ssl settings will sometimes result in server's rejection of the handshake and thereby the connection.
Here is an example of this kind of problem: parse-community/Parse-SDK-Android#430
Basically the clients (examples listed in the end) of the SSLSocketFactory are going to do more handhshake settings before they call the handshake function of the SSLSocket created by SSLSocketFactory. The
SSLCertificateSocketFactory is doing redundant work on this, and more than that, it may lead to the socket's breaking.

Some of the clients of SSLSocketFactory that set SSLSocket before handshake:
https://android.googlesource.com/platform/libcore/+/09f1b0c/luni/src/main/java/libcore/net/http/HttpConnection.java#204
https://android.googlesource.com/platform/external/okhttp/+/android-5.1.1_r36/okhttp/src/main/java/com/squareup/okhttp/Connection.java#166
@truclk
Copy link

truclk commented May 25, 2016

We have a same problem with CloudFlare, this is the library problem and happen randomly depends on the device. Is there any way to handle it or any update for this problem?

E//RegisterParsePushService.java:66(23453): IntentService[reg-parse-push] Parse - Error when syncing Parse installation
E//RegisterParsePushService.java:66(23453): com.parse.ParseRequest$ParseRequestException: i/o failure
E//RegisterParsePushService.java:66(23453):     at com.parse.ParseRequest.newTemporaryException(ParseRequest.java:290)
E//RegisterParsePushService.java:66(23453):     at com.parse.ParseRequest$2.then(ParseRequest.java:145)
E//RegisterParsePushService.java:66(23453):     at com.parse.ParseRequest$2.then(ParseRequest.java:139)
E//RegisterParsePushService.java:66(23453):     at bolts.Task$15.run(Task.java:917)
E//RegisterParsePushService.java:66(23453):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
E//RegisterParsePushService.java:66(23453):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
E//RegisterParsePushService.java:66(23453):     at java.lang.Thread.run(Thread.java:818)
E//RegisterParsePushService.java:66(23453): Caused by: javax.net.ssl.SSLHandshakeException: Handshake failed
E//RegisterParsePushService.java:66(23453):     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:392)
E//RegisterParsePushService.java:66(23453):     at android.net.SSLCertificateSocketFactory.verifyHostname(SSLCertificateSocketFactory.java:235)
E//RegisterParsePushService.java:66(23453):     at android.net.SSLCertificateSocketFactory.createSocket(SSLCertificateSocketFactory.java:488)
E//RegisterParsePushService.java:66(23453):     at com.squareup.okhttp.internal.io.RealConnection.connectTls(RealConnection.java:181)
E//RegisterParsePushService.java:66(23453):     at com.squareup.okhttp.internal.io.RealConnection.connectSocket(RealConnection.java:149)
E//RegisterParsePushService.java:66(23453):     at com.squareup.okhttp.internal.io.RealConnection.connect(RealConnection.java:112)
E//RegisterParsePushService.java:66(23453):     at com.squareup.okhttp.internal.http.StreamAllocation.findConnection(StreamAllocation.java:184)
E//RegisterParsePushService.java:66(23453):     at com.squareup.okhttp.internal.http.StreamAllocation.findHealthyConnection(StreamAllocation.java:126)
E//RegisterParsePushService.java:66(23453):     at com.squareup.okhttp.internal.http.StreamAllocation.newStream(StreamAllocation.java:95)
E//RegisterParsePushService.java:66(23453):     at com.squareup.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:281)
E//RegisterParsePushService.java:66(23453):     at com.squareup.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:224)
E//RegisterParsePushService.java:66(23453):     at com.squareup.okhttp.Call.getResponse(Call.java:286)
E//RegisterParsePushService.java:66(23453):     at com.squareup.okhttp.Call$ApplicationInterceptorChain.proceed(Call.java:243)
E//RegisterParsePushService.java:66(23453):     at com.squareup.okhttp.Call.getResponseWithInterceptorChain(Call.java:205)
E//RegisterParsePushService.java:66(23453):     at com.squareup.okhttp.Call.execute(Call.java:80)
E//RegisterParsePushService.java:66(23453):     at com.parse.ParseOkHttpClient.executeInternal(ParseOkHttpClient.java:69)
E//RegisterParsePushService.java:66(23453):     at com.parse.ParseHttpClient$ParseNetworkInterceptorChain.proceed(ParseHttpClient.java:158)
E//RegisterParsePushService.java:66(23453):     at com.parse.ParseDecompressInterceptor.intercept(ParseDecompressInterceptor.java:30)
E//RegisterParsePushService.java:66(23453):     at com.parse.ParseHttpClient$ParseNetworkInterceptorChain.proceed(ParseHttpClient.java:147)
E//RegisterParsePushService.java:66(23453):     at com.parse.ParsePlugins$1.intercept(ParsePlugins.java:115)
E//RegisterParsePushService.java:66(23453):     at com.parse.ParseHttpClient$ParseNetworkInterceptorChain.proceed(ParseHttpClient.java:147)
E//RegisterParsePushService.java:66(23453):     at com.parse.ParseHttpClient.execute(ParseHttpClient.java:122)
E//RegisterParsePushService.java:66(23453):     at com.parse.ParseRequest$3.then(ParseRequest.java:136)
E//RegisterParsePushService.java:66(23453):     at com.parse.ParseRequest$3.then(ParseRequest.java:133)
E//RegisterParsePushService.java:66(23453):     at bolts.Task$15.run(Task.java:917)
E//RegisterParsePushService.java:66(23453):     at bolts.BoltsExecutors$ImmediateExecutor.execute(BoltsExecutors.java:105)
E//RegisterParsePushService.java:66(23453):     at bolts.Task.completeAfterTask(Task.java:908)
E//RegisterParsePushService.java:66(23453):     at bolts.Task.continueWithTask(Task.java:715)
E//RegisterParsePushService.java:66(23453):     at bolts.Task.continueWithTask(Task.java:726)
E//RegisterParsePushService.java:66(23453):     at bolts.Task$13.then(Task.java:818)
E//RegisterParsePushService.java:66(23453):     at bolts.Task$13.then(Task.java:806)
E//RegisterParsePushService.java:66(23453):     ... 4 more
E//RegisterParsePushService.java:66(23453): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x8b4e1200: Failure in SSL library, usually a protocol error
E//RegisterParsePushService.java:66(23453): error:14077438:SSL routines:SSL23_GET_SERVER_HELLO:tlsv1 alert internal error (external/openssl/ssl/s23_clnt.c:765 0xace5abf9:0x00000000)
E//RegisterParsePushService.java:66(23453):     at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
E//RegisterParsePushService.java:66(23453):     at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:320)
E//RegisterParsePushService.java:66(23453):     ... 34 more

@abhijeet-aressindia
Copy link

@afterlastangel have you get any solution on this. I an getting the same exception, my Parse server is hosted on Heroku and signed by COMODO CA.

@paatz04
Copy link

paatz04 commented Dec 14, 2016

Any solutions on this ? I'm having the same issue and can't fix it

@totrit
Copy link

totrit commented Dec 14, 2016 via email

@paatz04
Copy link

paatz04 commented Dec 14, 2016

I could fix it! When looking into the parse 1.13.1 source code I realized they are still using http2. You have to update parse to 1.13.1 from mavenCentral and make sure it uses okHttp3. There has been an error with the jCenter 1.13.1 release which isn't mentioned anywhere. The build from maven is working.

this snippet in your projects gradle solved the issue for me:

`allprojects {

repositories {

    mavenCentral() // delete this line after Parse fixes

    jcenter()

}

}`

It pretty much tells gradle to use mavenCentral before jcenter in all your projects

Hope this helps!

@rogerhu
Copy link
Contributor

rogerhu commented Mar 7, 2017

1.13.1 should now be using okhttp3. You shouldn't have to add mavenCentral() now. Can we close this ticket?

@rogerhu
Copy link
Contributor

rogerhu commented Mar 8, 2017

This could also be related to: square/okhttp#2372

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants