Java中出现客户端认证SSL问题,缺少X.509证书。

3
我正在处理一个分布式应用程序中的服务器,该应用程序具有浏览器客户端,并且还参与与第三方的服务器到服务器通信。我的服务器拥有CA签名证书,以便我的客户端可以使用TLS(SSL)通信使用HTTP / S和XMPP(安全)进行连接。这一切都运行良好。
现在我需要安全地连接到第三方服务器。在此通信中,我的服务器充当客户端,我有一个由第三方签署的客户端证书。
问题是当我尝试添加从第三方服务器获取的客户端证书并使用标准系统配置(-Djavax.net.ssl.keyStore = xyz)时,我在SSL的调试日志中收到“没有用于客户端身份验证的X.509证书”错误。
javax.net.ssl|FINE|01|main|2021-09-15 02:07:40.538 IST|CertificateMessage.java:297|No X.509 certificate for client authentication, use empty Certificate message instead
javax.net.ssl|FINE|01|main|2021-09-15 02:07:40.538 IST|CertificateMessage.java:328|Produced client Certificate handshake message (
"Certificates": <empty list>
)

但是当我使用相同的密钥库来自定义SSL上下文时,它可以正常工作。以下是相应的代码。
                String keystorePath = "keystorePath";
                String keystorePassword = "changeit";

                // Make a KeyStore from the JKS file
                KeyStore ks = null;
                try {
                    ks = KeyStore.getInstance("JKS");
                } catch (KeyStoreException e) {
                    e.printStackTrace();
                }
                try (
                    FileInputStream fis = new FileInputStream(keystorePath)) {
                    ks.load(fis, keystorePassword.toCharArray());
                }

                TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
                tmf.init(ks);

                // Make a KeyManagerFactory from the KeyStore
                KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
                kmf.init(ks, keystorePassword.toCharArray());

                // Get hold of the default trust manager
                X509TrustManager x509Tm = null;
                for (TrustManager tm : tmf.getTrustManagers()) {
                    if (tm instanceof X509TrustManager) {
                        x509Tm = (X509TrustManager) tm;
                        break;
                    }
                }

                // Now make an SSL Context with our Key Manager and the default Trust Manager
                SSLContext sslContext = SSLContext.getInstance("TLS");
                sslContext.init(kmf.getKeyManagers(), null, null);
                return okHttpClient.newBuilder()
                        .sslSocketFactory(sslContext.getSocketFactory(), x509Tm)
                        .connectTimeout(10000, TimeUnit.MILLISECONDS)
                        .readTimeout(10000, TimeUnit.MILLISECONDS)
                        .build();

我希望只使用标准系统配置来管理密钥库,而不是自定义SSL上下文。


你也设置了 javax.net.ssl.keyStorePassword 吗? - erickson
是的,我也添加了密码。 - Anuj Kumar
你在什么时候设置了系统属性?它可能已经被读取:它们只会被读取一次并存储在变量中。相反,容器可能会在你之后设置它。你需要使用自定义的SSL上下文。 - user207421
@user207421 我通过命令行指定了系统属性,如下:-Djavax.net.ssl.keyStore=somepath -Djavax.net.ssl.keyStorePassword=pwd - Anuj Kumar
好的,我认为你必须坚持使用自定义代码。在事物的本质上,容器有权对系统属性进行任何喜欢的操作。 - user207421
我有同样的问题,你解决了吗? - Vincent Guyard
1个回答

2

当服务器的信任存储不正确时,我遇到了同样的问题。在上述SSL客户端日志之前,记录了“未选择RSA的X.509证书”和“没有可用的身份验证方案”。在此之前最大的线索是CertificateRequest中的“证书颁发机构”仅包含服务器证书的CN,而不是其CA的服务器CN。

另请参阅为什么Java在SSL握手期间不发送客户端证书?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接