一台服务器上的 Java SSLHandshakeException 而另一台服务器上没有?

标签 java ssl

为了调试最近出现在我们其中一台服务器上的 SSL 问题,我编写了一个非常简单的程序来连接到我们内联网中的 SSL 站点。

    URL authURL = null;
    BufferedReader br = null;
    String url = "https://our.server:443";

    try {
        authURL = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) 
                authURL.openConnection(); 
        conn.setDoOutput(false);
        conn.setDoInput(true);
        conn.setAllowUserInteraction(false);
        conn.setUseCaches(false);
        conn.connect();
    } catch (MalformedURLException urlEx) {
        urlEx.printStackTrace();
    } catch (IOException ex) {
        ex.printStackTrace();
    } finally {
        if (br != null) {
            try { br.close(); }
            catch (IOException e) {}
        }//if
    }//finally

此代码在我们的一台服务器上因 SSLHandshakeException 而失败,但完全相同的代码在另一台服务器上运行没有问题。我在启用 SSL 调试的情况下运行程序,这是每个服务器的结果

工作服务器 - SLES 11.3,Java IBM 1.6.0 64 位

... no IV used for this cipher
main, WRITE: SSLv3 Change Cipher Spec, length = 1
JsseJCE:  Using cipher RC4 from provider TBD via init
CipherBox:  Using cipher RC4 from provider from init IBMJCE version 1.2
JsseJCE:  Using MAC SslMacSHA1 from provider TBD via init
MAC:  Using MessageDigest SslMacSHA1 from provider IBMJCE version 1.2
*** Finished
verify_data:  { 101, 62, 81, 35, 

13, 178, 124, 13, 43, 0, 5, 248, 32, 15, 39, 244, 97, 96, 98, 227, 1 8, 172, 226, 53, 71, 218, 210, 21, 72, 85, 44, 130, 175, 194, 228, 34 }
***
main, WRITE: SSLv3 Handshake, length = 60
main, READ: SSLv3 Change Cipher Spec, length = 1
JsseJCE:  Using cipher RC4 from provider TBD via init
CipherBox:  Using cipher RC4 from provider from init IBMJCE version 1.2
JsseJCE:  Using MAC SslMacSHA1 from provider TBD via init
MAC:  Using MessageDigest SslMacSHA1 from provider IBMJCE version 1.2
main, READ: SSLv3 Handshake, length = 60
*** Finished
verify_data:  { 160, 27, 2, 24, 10, 15, 205, 204, 241, 225, 183, 150, 243, 244, 43, 107, 40, 112, 173  42, 122, 139, 225, 16, 33, 168, 255, 184, 23, 18, 69, 103, 19, 68, 182, 139 }
***
cached session [Session-1, SSL_RSA_WITH_RC4_128_SHA]
%% Cached client session: [Session-1, SSL_RSA_WITH_RC4_128_SHA]
main, WRITE: SSLv3 Application Data, length = 213
main, READ: SSLv3 Application Data, length = 402

不工作的服务器:Windows 7,Java JDK 1.6.0_39

   ... no IV used for this cipher
main, WRITE: SSLv3 Change Cipher Spec, length = 1
*** Finished
verify_data:  { 235, 130, 222, 201, 56, 225, 104, 77, 87, 210, 63, 16, 196, 223, 123, 231, 173, 146, 111, 102, 99, 214, 20, 244, 138, 79, 217, 140, 10, 61, 167, 9, 222, 95, 247, 208 }
***
main, WRITE: SSLv3 Handshake, length = 60
main, received EOFException: error
main, handling exception: javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
main, SEND SSLv3 ALERT:  fatal, description = handshake_failure
main, WRITE: SSLv3 Alert, length = 22
main, called closeSocket()
javax.net.ssl.SSLHandshakeException: Remote host closed connection during handshake
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:882)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1203)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1230)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1214)
    at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:434)
    at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:166)
    at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:133)
    at test.Main.main(Main.java:43)
Caused by: java.io.EOFException: SSL peer shut down incorrectly
    at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:333)
    at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:863)
    ... 7 more

有没有人知道我可以做些什么来让这个简单的代码在我的 Windows 7 机器上运行?我整天都在做这件事,现在很迷茫。感谢您的帮助!

更新 - 请求的 openssl 输出

工作服务器

CONNECTED(00000003)
depth=3 /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
verify return:1
depth=2 /C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
verify return:1
depth=1 /C=US/O=Thawte, Inc./CN=Thawte SGC CA - G2
verify return:1
depth=0 /C=US/ST=California/L=Riverside/O=University of California-Riverside/OU=Computing and Communication/CN=example.com
verify return:1
---
Certificate chain
 0 s:/C=US/ST=California/L=Riverside/O=University of California-Riverside/OU=Computing and Communication/CN=example.com
   i:/C=US/O=Thawte, Inc./CN=Thawte SGC CA - G2
 1 s:/C=US/O=Thawte, Inc./CN=Thawte SGC CA - G2
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
 2 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc. - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
 3 s:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
---

服务器不工作

    CONNECTED(0000018C)
depth=3 C = US, O = "VeriSign, Inc.", OU = Class 3 Public Primary Certification
Authority
verify error:num=19:self signed certificate in certificate chain
verify return:0
---
Certificate chain
 0 s:/C=US/ST=California/L=Riverside/O=University of California-Riverside/OU=Computing and Communication/CN=example.com
   i:/C=US/O=Thawte, Inc./CN=Thawte SGC CA - G2
 1 s:/C=US/O=Thawte, Inc./CN=Thawte SGC CA - G2
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc.
 - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
 2 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc.
 - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
 3 s:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
---

最佳答案

不同的结果可能是因为每台机器上的信任库略有不同。在这里,我假设您在服务器本地运行您的客户端,因此每个客户端都使用本地可用的 JVM。

但这并不能解释看起来很奇怪的链...

 0 s:/C=US/ST=California/L=Riverside/O=University of California-Riverside/OU=Computing and Communication/CN=example.com
   i:/C=US/O=Thawte, Inc./CN=Thawte SGC CA - G2
 1 s:/C=US/O=Thawte, Inc./CN=Thawte SGC CA - G2
   i:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc.
 - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
 2 s:/C=US/O=VeriSign, Inc./OU=VeriSign Trust Network/OU=(c) 2006 VeriSign, Inc.
 - For authorized use only/CN=VeriSign Class 3 Public Primary Certification Authority - G5
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
 3 s:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority
   i:/C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority

证书 0 是服务器的证书,显然它必须存在。

证书 1 是构建链所需的中间体。服务器也必须发送它。它必须发送它以避免 "which directory" problem .这是 PKI 中的一个众所周知的问题,这意味着客户端不知道去哪个目录寻找丢失的证书。

我在 Thawte root certificates 找不到证书 1 .证书 1 的颁发者是 VeriSign Class 3 Public Primary Certification Authority - G5

证书 2 是 VeriSign Class 3 Public Primary Certification Authority - G5。根据经验,我知道那是一个 CA,但我不确定它为什么声称拥有一个颁发者。

您可以从 Verisign Root Certifcates 下载 VeriSign Class 3 Public Primary Certification Authority - G5 .其文件名为 VeriSign-Class-3-Public-Primary-Certification-Authority-G5.pem。然后:

$ openssl x509 -in VeriSign-Class-3-Public-Primary-Certification-Authority-G5.pem -text -noout
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            18:da:d1:9e:26:7d:e8:bb:4a:21:58:cd:cc:6b:3b:4a
    Signature Algorithm: sha1WithRSAEncryption
        Issuer: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5
        Validity
            Not Before: Nov  8 00:00:00 2006 GMT
            Not After : Jul 16 23:59:59 2036 GMT
        Subject: C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, CN=VeriSign Class 3 Public Primary Certification Authority - G5
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:af:24:08:08:29:7a:35:9e:60:0c:aa:e7:4b:3b:
                    ...
                    25:15
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Basic Constraints: critical
                CA:TRUE
            X509v3 Key Usage: critical
                Certificate Sign, CRL Sign
            1.3.6.1.5.5.7.1.12: 
                0_.].[0Y0W0U..image/gif0!0.0...+..............k...j.H.,{..0%.#http://logo.verisign.com/vslogo.gif
            X509v3 Subject Key Identifier: 
                7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33
    Signature Algorithm: sha1WithRSAEncryption
         93:24:4a:30:5f:62:cf:d8:1a:98:2f:3d:ea:dc:99:2d:bd:77:
         ...
         a8:ed:63:6a

注意它是一个 CA:主题和颁发者是相同的,有一个基本约束,CA:true 被标记为关键,等等。

所以我认为您可能使用的是旧的 Verisign 证书。它甚至可能已过期。但是您可以访问它,所以只有您自己知道。

现在,这里是真正奇怪的地方:证书 3 和 Class 3 Public Primary Certification Authority。它也是一个 CA,但它不证明任何东西。

所以,我会做以下事情:

  1. 从链中删除证书 2
  2. 从链中删除证书 3
  3. VeriSign Class 3 Public Primary Certification Authority - G5 添加到信任库
  4. 使用 OpenSSL 测试两台服务器

测试:首先,从 Verisign Root Certifcates 下载 VeriSign Class 3 Public Primary Certification Authority - G5 .其文件名为 VeriSign-Class-3-Public-Primary-Certification-Authority-G5.pem

针对每个服务器第二次运行 openssl s_client(如下所示的命令)。包含 CAfile 选项以指定 Verisign 信任 anchor 。使用所需的信任 anchor ,它应该以:Verify return code: 0 (ok) 结束。

$ openssl s_client -connect example.com:443 -CAfile VeriSign-Class-3-Public-Primary-Certification-Authority-G5.pem
...
Start Time: 1407273676
Timeout   : 300 (sec)
Verify return code: 0 (ok)

openssl s_client 将从循环中删除 Java,并允许您验证您是否有一个“已知良好”的基线,以便在 Java 中进行进一步测试。但我怀疑您在行为不当的服务器的证书存储中有一个旧的 Verisign 根,或者您在行为不当的服务器的证书存储中缺少所需的根,或者两者兼而有之。

关于一台服务器上的 Java SSLHandshakeException 而另一台服务器上没有?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25147435/

相关文章:

java - 当我尝试返回多维数组中某个项目的索引值时,我没有得到数字。我得到了一组奇怪的字符。为什么?

java - Http status 404 -/请求的资源不可用

java - Adcolony 与 Android Studio

java - 编写 int 数组并返回元素数量的正确方法?

ruby-on-rails - 瘦启动 ssl 抛出无效的解析错误

android - 在 RoboSpice 中仅将 TLS 与 Retrofit 结合使用

java - 如何从字符串矩阵中获取元素的 int 值?

ssl - Tokio Tls 自签名证书

apache - 为 XAMPP 配置 SSL

sockets - Erlang 提示和技巧减少 gen_server ssl 套接字的内存占用