【问题标题】:Two way SSL digital certificate authentication is failing in Java 6 but working in Java 7两种方式的 SSL 数字证书身份验证在 Java 6 中失败但在 Java 7 中工作
【发布时间】:2016-02-17 18:51:45
【问题描述】:

我有一个 Java 程序通过 2 路 SSL 证书身份验证连接到服务器。它在 Java 7 上运行良好,但在 Java 6 上失败。不幸的是,我们的系统仍在使用 Java 6。所以,我正在尝试让它在 Java 6 上运行。

在 SSL 相互身份验证事务的第一步连接失败。这是 ClientHello 步骤。我们收到来自服务器的致命错误。根据我的分析,我觉得这个问题可能与不受支持的密码套件有关(即服务器不支持客户端发送的密码套件),但不确定。

我尝试使用 System.setProperty("javax.net.debug", "ssl:handshake"); 来调试问题,但调试信息指向特定问题。

我什至无法获取 Java 6 中安全类的源代码(例如:com.sun.net.ssl.internal.ssl.* 包)以在代码中进行调试。

这里是 ssl 调试日志:

*** ClientHello, TLSv1
RandomCookie:  GMT: 1438890076 bytes = { 65, 109, 167, 225, 235, 81, 235, 118, 35, 88, 126, 146, 201, 181, 233, 118, 222, 126, 190, 170, 247, 232, 166, 222, 98, 157, 165, 150 }
Session ID:  {}
Cipher Suites: [SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
Compression Methods:  { 0 }
***
main, WRITE: TLSv1 Handshake, length = 81
main, WRITE: SSLv2 client hello message, length = 110
main, READ: TLSv1 Alert, length = 2
main, RECV TLSv1 ALERT:  fatal, handshake_failure
main, called closeSocket()
main, handling exception: javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
Exception in thread "main" javax.net.ssl.SSLHandshakeException:     Received fatal alert: handshake_failure
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:136)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:1822)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1004)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1188)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1215)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1199)
at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:476)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1195)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
at com.castlight.ws.healthfund.welsforgo.WellsForgoTester_JDK6.main(WellsForgoTester_JDK6.java:72)

如何具体找出问题所在?有没有办法调试 Java 6 安全代码(例如:com.sun.net.ssl.internal.ssl.* 包)?

【问题讨论】:

  • 您是否查看了文档以了解 Java 6 说明应该如何完成这项工作?有什么区别?
  • 您是否设置了用于此连接的SSLSocketFactory?您如何控制启用的 TLS 协议、密码套件等?
  • 我敢打赌服务器不处理 SSLv2-format hello,而不是看起来不错的密码,Java6 JSSE 默认使用它(尽管仅用于协商更新/更好的协议)。由于您使用的是 HttpsURLConnection,请尝试设置 sysprop https.protocols=SSLv3,TLSv1 。
  • @dave_thompson_085:是的,Java 6 似乎不支持 SSLv2。事实上,我正在使用 TLSv1 协议 (sslContext = SSLContext.getInstance("TLSv1");) 创建 sslContext,但仍然选择 SSLv2 来打招呼。这似乎是 java 6 中的一个问题。现在,它通过使用系统属性 https.protocols=TLSv1 将协议限制为 TLSv1 或通过配置 SSLSocket 对象(socket.setEnabledProtocols( new String[]{"TLSv1"});) 非常感谢您的帮助。
  • Java 的早期版本很混乱。另见Which Cipher Suites to enable for SSL Socket?

标签: java ssl ssl-certificate ws-security mutual-authentication


【解决方案1】:

首先你需要知道jdk1.6.115以下的java 6不支持TLSv1.2。您需要升级 JDK 版本。另请注意,您不能通过代码中的系统属性设置 TLSv1.2。您将需要使用您的代码明确设置它。您需要在调用 API 之前在密钥库中设置 TLSv1.2 属性。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-04-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-02
    • 2012-05-22
    • 1970-01-01
    • 2012-06-23
    • 2017-06-28
    相关资源
    最近更新 更多