禁用双向SSL中的证书链验证

时间:2017-03-30 09:25:20

标签: java ssl https handshake truststore

我指的是这个问题的第二个答案:

Web Service Client (JAX-WS) in Weblogic(10.3) with 2 way SSL cannot complete the handshake

我有一个客户端程序,通过单向SSL连接到另一台服务器A.为了关闭证书链验证,我在上述问题的第二个答案中使用了解决方案来安装一个完全信任的信任管理器。它工作正常。

但是,当客户端程序使用双向SSL连接到另一台服务器B时,将引发以下异常。

java.net.SocketException: Software caused connection abort: recv failed
        at java.net.SocketInputStream.socketRead0(Native Method)
        at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
        at java.net.SocketInputStream.read(SocketInputStream.java:171)
        at java.net.SocketInputStream.read(SocketInputStream.java:141)
        at sun.security.ssl.InputRecord.readFully(InputRecord.java:465)
        at sun.security.ssl.InputRecord.read(InputRecord.java:503)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:973)
        at sun.security.ssl.SSLSocketImpl.waitForClose(SSLSocketImpl.java:1769)
        at sun.security.ssl.HandshakeOutStream.flush(HandshakeOutStream.java:124
)
        at sun.security.ssl.Handshaker.sendChangeCipherSpec(Handshaker.java:1130
)
        at sun.security.ssl.ClientHandshaker.sendChangeCipherAndFinish(ClientHan
dshaker.java:1216)
        at sun.security.ssl.ClientHandshaker.serverHelloDone(ClientHandshaker.ja
va:1128)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.jav
a:348)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:1026)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:961)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.
java:1375)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403
)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387
)
        at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:
559)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect
(AbstractDelegateHttpsURLConnection.java:185)
        at sun.net.www.protocol.http.HttpURLConnection.getOutputStream0(HttpURLC
onnection.java:1316)
        at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLCo
nnection.java:1291)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(Htt
psURLConnectionImpl.java:250)

如果我没有安装所有信任的信任管理器,我仍然可以连接到两个服务器(无论是单向还是双向SSL),前提是我指定了标识存储和信任存储:

System.setProperty("javax.net.ssl.keyStore", "path/to/your/key");
System.setProperty("javax.net.ssl.keyStorePassword", "your-keystore-password");
System.setProperty("javax.net.ssl.keyStoreType", "JKS");
System.setProperty("javax.net.ssl.trustStore", "path/to/your/trust/keystore");
System.setProperty("javax.net.ssl.trustStorePassword", "your-truststore-password");

但是,我仍然希望在双向SSL中关闭证书链验证。安装所有信任的信任管理器似乎不起作用。为什么呢?

提前致谢。

2 个答案:

答案 0 :(得分:0)

  

但是,我仍然希望关闭证书链验证   双向SSL。似乎没有安装所有信任的信任管理器   上班。为什么呢?

服务器要求您提供识别客户端证书。如果您的客户端没有提供服务器配置为接受的证书,则会丢失您的连接尝试。

你根本无法在客户端改变这一点。

SSL协议的设计使得如果客户端或服务器要求另一方用证书来标识自己,则不能由提供证书所需的一方修改。

答案 1 :(得分:0)

我知道现在的问题在哪里。在链接中提供的解决方案中,有以下几行来安装所有信任的信任管理器:

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

问题在于sc.init调用。第一个参数是密钥管理器列表。需要至少一个密钥管理器来返回客户端的身份,以便可以将其发送到服务器以进行客户端身份验证。在上面的代码中,密钥管理器设置为null,这意味着没有可以发送到服务器进行客户端身份验证的客户端标识。这就是为什么它会在客户端身份验证失败,但会通过服务器身份验证(因为安装了所有信任的信任管理器)。

这是我们初始化身份密钥库并将其设置为SSL上下文的方法:

KeyStore keyStore = KeyStore.getInstance("JKS");
FileInputStream fileInputStream = new FileInputStream("identity key store full path name");
keyStore.load(fileInputStream, "identity key store password".toCharArray());
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, "identity key store password".toCharArray());
KeyManager[] keyManagers = keyManagerFactory.getKeyManagers();
sc.init(keyManagers, trustAllCerts, new java.security.SecureRandom());