-2

I got a multiplayer game with a client server setup that has been working fine on Desktop and my own Android test devices (4.x - 5.x) but everyone that have tried using a mobile device with Android 6+ can not complete a handshake with the server.

The client get: Connection closed by peer exception in com.android.org.conscrypt.SSL_do_handshake(Native Method)

I turned on full output for the javax.net package on the server and this is what I see:

Thread-5, called closeInbound()
Thread-5, fatal error: 80: Inbound closed before receiving peer's close_notify: possible truncation attack?
javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack?
%% Invalidated:  [Session-1, TLS_DHE_RSA_WITH_AES_128_CBC_SHA]
Thread-5, SEND TLSv1.2 ALERT:  fatal, description = internal_error
Thread-5, WRITE: TLSv1.2 Alert, length = 2
Thread-5, called closeOutbound()
Thread-5, closeOutboundInternal()

Log is actually 90k+ chars but I could not paste it all. But basically server client goes through TLS1.2, 1.1 and 1.0 and the result is the same "javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack?"

I am using an self signed certificate and the truststore hack:

    public LoginClient() throws Exception{
             // Create a trust manager that does not validate certificate chains
            TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
//                      return null;
                        return new X509Certificate[0];
                    }
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    }
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    }
                }
            };

            // Install the all-trusting trust manager
            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

            // Create all-trusting host name verifier
            HostnameVerifier allHostsValid = new HostnameVerifier() {
                public boolean verify(String hostname, SSLSession session) {
                    return true;
                }
            };

            // Install the all-trusting host verifier
            HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);

        }

Does anyone have any idea what is going wrong and how I can fix this? I find it a bit strange that it only occurs for Android 6+

Edit: Added the *** Diffie-Hellman ServerKeyExchange

DH Modulus:  { 233, 230, 66, 89, 157, 53, 95, 55, 201, 127, 253, 53, 103, 18, 11, 142, 37, 201, 205, 67, 233, 39, 179, 169, 103, 15, 190, 197, 216, 144, 20, 25, 34, 210, 195, 179, 173, 36, 128, 9, 55, 153, 134, 157, 30, 132, 106, 171, 73, 250, 176, 173, 38, 210, 206, 106, 34, 33, 157, 71, 11, 206, 125, 119, 125, 74, 33, 251, 233, 194, 112, 181, 127, 96, 112, 2, 243, 206, 248, 57, 54, 148, 207, 69, 238, 54, 136, 193, 26, 140, 86, 171, 18, 122, 61, 175 }
DH Base:  { 48, 71, 10, 213, 160, 5, 251, 20, 206, 45, 157, 205, 135, 227, 139, 199, 209, 177, 197, 250, 203, 174, 203, 233, 95, 25, 10, 167, 163, 29, 35, 196, 219, 188, 190, 6, 23, 69, 68, 64, 26, 91, 44, 2, 9, 101, 216, 194, 189, 33, 113, 211, 102, 132, 69, 119, 31, 116, 186, 8, 77, 32, 41, 216, 60, 28, 21, 133, 71, 243, 169, 241, 162, 113, 91, 226, 61, 81, 174, 77, 62, 90, 31, 106, 112, 100, 243, 22, 147, 58, 52, 109, 63, 82, 146, 82 }
Server DH Public Key:  { 23, 79, 111, 200, 124, 159, 143, 170, 244, 139, 127, 154, 15, 184, 207, 89, 0, 30, 234, 138, 254, 90, 48, 244, 171, 46, 100, 55, 220, 87, 23, 2, 3, 243, 132, 144, 17, 75, 191, 90, 239, 112, 13, 71, 150, 127, 34, 219, 174, 161, 188, 204, 151, 97, 179, 129, 103, 89, 188, 211, 14, 216, 71, 115, 12, 105, 63, 219, 23, 70, 110, 231, 202, 153, 121, 59, 194, 97, 105, 215, 57, 211, 48, 184, 22, 149, 176, 64, 186, 103, 240, 237, 224, 217, 233, 4 }
Signature Algorithm SHA512withRSA
Signed with a DSA or RSA public key
*** ServerHelloDone

Update I finally got hold of an Android 6.0.1 device so I could test this some more. In my development environment I run Oracle Java 7u25 on the production server there is openjdk 7 and the funny thing is that Android 6 works in my development environment with the exact same setup but fails when I try to connect to the production server. I can now see the full exception and it is:

11-01 05:18:50.793: W/System.err(23793): javax.net.ssl.SSLHandshakeException: Handshake failed
11-01 05:18:50.796: W/System.err(23793):    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:396)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.http.SocketConnector.connectTls(SocketConnector.java:103)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.Connection.connect(Connection.java:143)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.Connection.connectAndSetOwner(Connection.java:185)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.OkHttpClient$1.connectAndSetOwner(OkHttpClient.java:128)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.http.HttpEngine.nextConnection(HttpEngine.java:341)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:330)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:248)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:437)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:114)
11-01 05:18:50.796: W/System.err(23793):    at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getOutputStream(HttpURLConnectionImpl.java:245)
11-01 05:18:50.797: W/System.err(23793):    at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getOutputStream(DelegatingHttpsURLConnection.java:218)
11-01 05:18:50.797: W/System.err(23793):    at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getOutputStream(HttpsURLConnectionImpl.java)
11-01 05:18:50.797: W/System.err(23793):    at com.aperico.game.sylvass.netcode.LoginClient.doLogin(LoginClient.java:105)
11-01 05:18:50.797: W/System.err(23793):    at com.aperico.game.sylvass.CryptCardsGame$4.run(CryptCardsGame.java:343)
11-01 05:18:50.797: W/System.err(23793):    at java.lang.Thread.run(Thread.java:818)
11-01 05:18:50.797: W/System.err(23793):    Suppressed: javax.net.ssl.SSLHandshakeException: Handshake failed
11-01 05:18:50.797: W/System.err(23793):        ... 16 more
11-01 05:18:50.797: W/System.err(23793):        Suppressed: javax.net.ssl.SSLHandshakeException: Handshake failed
11-01 05:18:50.797: W/System.err(23793):            ... 16 more
11-01 05:18:50.798: W/System.err(23793):        Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x941df080: Failure in SSL library, usually a protocol error
11-01 05:18:50.798: W/System.err(23793): error:100c1069:SSL routines:ssl3_get_server_key_exchange:BAD_DH_P_LENGTH (external/boringssl/src/ssl/s3_clnt.c:1193 0xa9e31ad5:0x00000000)
11-01 05:18:50.798: W/System.err(23793):            at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
11-01 05:18:50.798: W/System.err(23793):            at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)
11-01 05:18:50.798: W/System.err(23793):            ... 15 more
11-01 05:18:50.798: W/System.err(23793):    Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x941df080: Failure in SSL library, usually a protocol error
11-01 05:18:50.798: W/System.err(23793): error:100c1069:SSL routines:ssl3_get_server_key_exchange:BAD_DH_P_LENGTH (external/boringssl/src/ssl/s3_clnt.c:1193 0xa9e31ad5:0x00000000)
11-01 05:18:50.798: W/System.err(23793):        at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
11-01 05:18:50.799: W/System.err(23793):        at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)
11-01 05:18:50.799: W/System.err(23793):        ... 15 more
11-01 05:18:50.799: W/System.err(23793): Caused by: javax.net.ssl.SSLProtocolException: SSL handshake aborted: ssl=0x941df080: Failure in SSL library, usually a protocol error
11-01 05:18:50.799: W/System.err(23793): error:100c1069:SSL routines:ssl3_get_server_key_exchange:BAD_DH_P_LENGTH (external/boringssl/src/ssl/s3_clnt.c:1193 0xa9e31ad5:0x00000000)
11-01 05:18:50.799: W/System.err(23793):    at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
11-01 05:18:50.799: W/System.err(23793):    at com.android.org.conscrypt.OpenSSLSocketImpl.startHandshake(OpenSSLSocketImpl.java:324)
11-01 05:18:50.799: W/System.err(23793):    ... 15 more
  • 1
    Why do you use SSL at all if your effectively disable certificate validation? Apart from that it might be a weak DH key but there are not enough details (like server name) to find out. – Steffen Ullrich Oct 30 '16 at 17:18
  • @SteffenUllrich No server name only IP so I can not use ssllabs.com for example. I can provide any info needed but I could not paste it all at once due to size restrictions. I added the DH details in an edit above. – Andreas Toresäter Oct 31 '16 at 03:33

2 Answers2

2

Server DH Public Key: { ... 96 numbers between 0 and 255 ... }

Your DH key is only 768 bit (96*8). This is considered to weak, see logjam attack for details. Therefore modern TLS stacks including most modern web browsers require the DH keys to be at least 1024 bit.

My guess is that you are using Java 7 on the server since 768 bit DH key is the default there, while with Java 8 the default is 1024 bit. According to How Java 7 and 8 Handle DHE Keys Differently, and Resolving Errors Java 7 cannot use DH keys with 1024 bit and better which means your choices are to either upgrade to Java 8 or to disable ciphers using DH. How to do the latter is also described in this article.

Apart from that it is a very bad idea to disable hostname validation in the client like you do. This means effectively that you trust any certificate issued by a trusted CA, no matter for which host this certificate is valid. This make man in the middle attacks easy and thus effectively removes the major part of the protection offered by TLS. If you have a certificate which could not be trusted otherwise use instead certificate pinning to accept only this certificate in your application and to deter man in the middle attacks. See OWASP for more information including example code for a variety of languages including Java.

Community
  • 1
  • 1
Steffen Ullrich
  • 114,247
  • 10
  • 131
  • 172
  • OK, thank you I am using j7 on server and will try this solution out. Thank you also for pointing out the security issues, I am aware of those but have not decided how to plug them. Using HttpsURLConnection.setDefaultHostnameVerifier(myHostIPOnly); would not either be enough I guess? – Andreas Toresäter Oct 31 '16 at 06:05
  • 1
    @Korpen: if you have a valid certificate for this specific IP address then restricting the hostname verifier to make sure that this IP address must be included in the certificate would work too as long as nobody is able to get a certificate for this IP address too. But, usually you don't get certificates for IP addresses (at least not from public CA) and apart from that chances are high that the IP address will change in the future. – Steffen Ullrich Oct 31 '16 at 06:10
  • I tried to change the allowed ciphers as described in the link you gave above. The server logs now show it using TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 but it still does not work for my testers using Android 6.0. I also saw something I missed and that is that when I for example log in from my Win7/64 machine it works on first try with TLSv1.2 but the the server logs still shows the "javax.net.ssl.SSLException: Inbound closed before receiving peer's close_notify: possible truncation attack?" message – Andreas Toresäter Oct 31 '16 at 11:39
  • The problem with Win7 is probably because the client closes since it receives an invalid certificate and will reconnect once the user added an exception. If your server is public reachable and you could provide its URL one might maybe find out more about the problem. – Steffen Ullrich Oct 31 '16 at 13:02
  • On Win7 it does work, it just gives the same warning about possible truncation attack. I found sslshopper.com that can test ip addresses and it said the certificate is good. I have updated my question, please take a look at it and see if you can think of anything more? – Andreas Toresäter Nov 01 '16 at 04:22
  • @Korpen: Obviously DH ciphers are not completely switched off since Android 6 is exactly complaining about weak DH according to your debug output: BAD_DH_P_LENGTH – Steffen Ullrich Nov 01 '16 at 04:47
0

Updating to Oracle Java 8 on the server solved this problem. Not entierly sure why but it seems Android 6+ is not able to negotiate a handshake with openjdk 7