tl;dr:使用自定义 CA 而不将其添加到持久密钥库。
我正在编写一个应该使用 HTTPS 连接到远程服务器的 Java 应用程序。连接的代码已经准备好,但是服务器的 SSL 证书是由StartSSL签名的,它不在 Java 的 CA 根证书存储中。
使用此代码,我可以从以下网站获得有效的证书信息https://www.google.com/
:
Response Code : 200
Cipher Suite : TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
Cert Type : X.509
Cert Hash Code : -1643391404
Cert Public Key Algorithm : RSA
Cert Public Key Format : X.509
Cert Type : X.509
Cert Hash Code : 771393018
Cert Public Key Algorithm : RSA
Cert Public Key Format : X.509
Cert Type : X.509
Cert Hash Code : 349192256
Cert Public Key Algorithm : RSA
Cert Public Key Format : X.509
相同的代码会为我的域抛出一个SSLHandshakeException
(我们称之为https://www.example.com/
)。
当然,我可以使用keytool
(甚至可能使用Runtime.exec("keytool ...")
)手动将证书添加到密钥库,但这是一种肮脏的方式。我现在计划将 StartSSL 根证书添加到我的应用程序文件中以进行分发,然后在运行时将其加载到一些临时密钥库中。这样,“真正的”密钥库保持不变。
根据我在这里和这里所读到的内容,我将不得不搞砸一些课程,例如TrustManager
。我什至找到了一种完全关闭验证的方法,但这不是我想要的,因为它似乎消除了加密通信的全部目的。
我什至发现一些代码行似乎完全符合我的要求,但我无法弄清楚如何调用此方法,即哪些值作为参数传递:
public class SSLClasspathTrustStoreLoader {
public static void setTrustStore(String trustStore, String password) throws Exception {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream keystoreStream = SSLClasspathTrustStoreLoader.class.getResourceAsStream(trustStore);
keystore.load(keystoreStream, password.toCharArray());
trustManagerFactory.init(keystore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustManagers, null);
SSLContext.setDefault(sc);
}
}
以前有没有人遇到过类似的情况?我将不胜感激有关如何处理此问题的任何建议。如果您甚至可以帮助我运行上述代码,我会非常高兴!