在 Java CXF 客户端中实施 Two-Way SSL

Enforce Two-Way SSL in Java CXF clients

Two-Way SSL - 或相互身份验证 - 通常由服务器在 HTTPS 中指定。例如,this tutorial 解释了如何设置 WildFly 应用程序服务器以要求网络服务客户端在通信期间出示证书。

但是,在我们的例子中,我们需要在客户端强制执行 Two-Way SSL。这意味着我们的客户端配置了客户端证书,以便它可以在握手期间提供证书。如果我们连接的服务器不要求证书,我们想中止通信。

SSL 握手的描述,如标题为 "The SSL Protocol" here 的部分中的图表(稍微往下)解释了发生的第一件事是如何选择密码套件:

"1. Client hello - The client sends the server information including the highest version of SSL it supports and a list of the cipher suites it supports. (TLS 1.0 is indicated as SSL 3.1.) The cipher suite information includes cryptographic algorithms and key sizes."

在 Java 方面(更具体地说:在我的例子中是 CXF),可以 filter cipher suites("cipherSuitesFilter") - so I thought it would be possible to limit cipher suites to those requiring mutual authentication. But I don't find any links between cipher suites and two-way SSL. For example, this page 注释:

authentication algorithm - dictates how server authentication and (if needed) client authentication will be carried out.

我开始认为这意味着密码套件仅指示 如何 客户端身份验证完成,而不是 if 需要客户端身份验证.

这让我陷入了死胡同。有没有其他方法可以在客户端强制执行客户端身份验证?

目前我能想到的唯一解决方案是在握手完成后找到正确的 hook 方法来实现 SSL 通信,检查连接是否使用客户端身份验证,如果没有则中止。但如果存在这种情况,我想使用任何一种通用方法。

我们没有找到比我在问题中已经提到的更好的解决方案。 作为客户端,我们只能检查是否使用客户端证书建立了连接。这并不能保证服务器彻底验证了证书,只是它请求了证书。

我们的实现是一个自定义 javax.net.ssl.SSLSocketFactory,它扩展了 createSocket 方法来检查是否 javax.net.ssl.SSLSession.getLocalCertificates() returns 某些东西。如果不是,则抛出 javax.net.ssl.SSLException 的异常子类以中止通信。 套接字工厂通过 org.apache.cxf.configuration.jsse.TLSClientParameters.setSSLSocketFactory(SSLSocketFactory).

设置