简体   繁体   中英

Java 1.8: TLSv1.2 ClientHello handshake failure (missing elliptical curve extensions?)

I'm working in java1.8 and connecting to APNS (api.push.apple.com) via OKHTTP.

The symptom is a failing SSL handshake: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure , which according to my research indicates the server couldn't negotiate a cipher with the client.

The code is just creating an SSL context via SSLContext.getInstance("TLS") .

After running my application with -Djavax.net.debug=all , I found that the my SSL handshake ClientHello looks like this:

*** ClientHello, TLSv1.2
RandomCookie:  GMT: 1500317763 bytes = { 59, 94, 246, 29, 243, 123, 94, 45, 2, 86, 47, 12, 198, 219, 164, 71, 166, 30, 143, 25, 190, 34, 243, 50, 24, 239, 0, 131 }
Session ID:  {}
Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_128_GCM_SHA256, TLS_RSA_WITH_AES_128_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA]
Compression Methods:  { 0 }
Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA256withDSA, SHA224withECDSA, SHA224withRSA, SHA224withDSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA
Extension server_name, server_name: [type=host_name (0), value=api.push.apple.com]
Extension renegotiation_info, renegotiated_connection: <empty>
Extension application_layer_protocol_negotiation, protocols: [h2, spdy/3.1, http/1.1]
***

which is basically just followed up with a

OkHttp https://api.push.apple.com/3/device/token, READ: TLSv1.2 Alert, length = 2
OkHttp https://api.push.apple.com/3/device/token, RECV TLSv1.2 ALERT:  fatal, handshake_failure

The puzzling thing is that the code is running successfully on a coworker's laptop - the SSL ClientHello is identical except it includes following two entries:

Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}
Extension ec_point_formats, formats: [uncompressed]

Analyzing SSL for the APNS server ( https://www.ssllabs.com/ssltest/analyze.html?d=api.push.apple.com&s=17.188.154.31 ) shows that it only accepts TLSv1.2 and the following ciphers:

TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 (0xcca8)   ECDH secp256r1 (eq. 3072 bits RSA)   FS  256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)   ECDH secp256r1 (eq. 3072 bits RSA)   FS    256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)   ECDH secp256r1 (eq. 3072 bits RSA)   FS    128

which makes me think that the missing Extension s in the SSL handshake are causing the server to reject my handshake on the basis of not having a common cipher to use.


The laptop on which this runs is OS X 10.10, whereas the one in which it's broken is macOS 10.12. We're both on Java1.8.


If anyone has any leads on on this it would be greatly appreciated.

Thanks for your time.

Probably the absent EC extensions are what's causing the problem, although technically it's permitted - see RFC 4492 section 4:

A client that proposes ECC cipher suites may choose not to include these extensions. In this case, the server is free to choose any one of the elliptic curves or point formats listed in Section 5.

That can still go wrong, but presumably not before you receive the server's first flight (ServerHello ... ServerHelloDone), so I assume the server doesn't permit this absence.

I think it is pretty strange behaviour for JDK8 to not send that extension, so I expect your JDK is configured strangely in some way and it might be best to install and test a brand new JDK8 (unmodified except for installing the "JCE Unlimited Strength" policy files).

I briefly looked at the (OpenJDK) JDK8 source, and there are a couple of possibilities for why this extension might be absent:

  • Somehow the JCE cryptographic provider for "EC" is missing or doesn't support TLS curves. Review your jre/lib/security/java.security list of security.provider entries, and any programmatic provider changes you're making. Are you trying to use some sort of hardware token for client authentication?
  • Perhaps you've got "jdk.tls.namedGroups" system property set (if it was empty, you should be seeing an exception, but maybe you've listed only unsupported curves). Check any other system properties you might have set.

According to the source code there may be a line in your debug log generated by the failure to find any curves:

        if (debug != null && idList.isEmpty()) {
        debug.println(
            "Initialized [jdk.tls.namedGroups|default] list contains " +
            "no available elliptic curves. " +
            (property != null ? "(" + property + ")" : "[Default]"));
    }

Please report whether you see that message, and what it says. It might also be helpful to know the exact JDK8 version you're using and whether you've got FIPS mode enabled.

The ALPN library in your bootclasspath replaces SSL code in the JDK with a patched version. That means the you break the JDK when the JDK is updated and ALPN remains at an old version!

Check which ALPN version you need for your JDK in the mapping file: https://github.com/jetty-project/jetty-alpn/tree/master/docs

All ALPN JARs can be found here: http://repo1.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM