我在java1.8工作并通过OKHTTP连接到APNS(api.push.apple.com)。
症状是SSL握手失败:javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
,根据我的研究表明,服务器无法与客户端协商密码。
代码只是通过SSLContext.getInstance("TLS")
创建SSL上下文。
使用-Djavax.net.debug=all
运行我的应用程序后,我发现我的SSL握手ClientHello看起来像这样:
*** 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]
***
基本上只是跟着
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
令人费解的是,代码在同事的笔记本电脑上成功运行 - SSL ClientHello完全相同,但它包括以下两个条目:
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]
分析APNS服务器的SSL(https://www.ssllabs.com/ssltest/analyze.html?d=api.push.apple.com&s=17.188.154.31)表明它只接受TLSv1.2和以下密码:
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
这让我觉得SSL握手中丢失的Extension
导致服务器在没有使用公共密码的情况下拒绝我的握手。
运行它的笔记本电脑是OS X 10.10,而它破坏的笔记本电脑是macOS 10.12。我们都在Java1.8上。
如果有人对此有任何线索,我们将不胜感激。
感谢您的时间。
答案 0 :(得分:2)
可能缺少的EC扩展是造成问题的原因,虽然从技术上讲是允许的 - 参见RFC 4492第4节:
建议ECC密码套件的客户可以选择不包括 这些扩展。在这种情况下,服务器可以自由选择任何一个 第5节中列出的椭圆曲线或点格式。
这仍然可能出错,但可能在你收到服务器的第一个航班(ServerHello ... ServerHelloDone)之前,所以我假设服务器不允许这种缺席。
我认为JDK8不发送该扩展名是非常奇怪的行为,所以我希望你的JDK以某种方式配置奇怪,最好安装和测试一个全新的JDK8(除了安装“JCE”之外没有修改)无限强度“政策文件”。
我简要地查看了(OpenJDK)JDK8源代码,并且有几种可能性可以解释为什么不能使用此扩展:
根据源代码,调试日志中可能会有一行由于找不到任何曲线而生成:
if (debug != null && idList.isEmpty()) {
debug.println(
"Initialized [jdk.tls.namedGroups|default] list contains " +
"no available elliptic curves. " +
(property != null ? "(" + property + ")" : "[Default]"));
}
请报告您是否看到该消息及其内容。了解您正在使用的确切JDK8版本以及是否已启用FIPS模式可能也会有所帮助。
答案 1 :(得分:0)
bootclasspath中的ALPN库使用修补版本替换JDK中的SSL代码。这意味着当JDK更新并且ALPN保持旧版本时,您将破坏JDK!
在映射文件中检查JDK所需的ALPN版本: https://github.com/jetty-project/jetty-alpn/tree/master/docs
所有ALPN JAR都可以在这里找到: http://repo1.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/