您可以使用X509TrustManager 来实现这一点。
使用
获取 SSLContext
SSLContext ctx = SSLContext.getInstance("TLS");
然后使用您的自定义X509TrustManager 使用SSLContext#init 对其进行初始化。 SecureRandom 和 KeyManager[] 可能为空。后者仅在您执行客户端身份验证时有用,如果在您的场景中只有服务器需要进行身份验证,您不需要设置它。
从此 SSLContext 中,使用 SSLContext#getSocketFactory 获取您的 SSLSocketFactory 并按计划进行。
就您的 X509TrustManager 实现而言,它可能如下所示:
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
//do nothing, you're the client
}
public X509Certificate[] getAcceptedIssuers() {
//also only relevant for servers
}
public void checkServerTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
/* chain[chain.length -1] is the candidate for the
* root certificate.
* Look it up to see whether it's in your list.
* If not, ask the user for permission to add it.
* If not granted, reject.
* Validate the chain using CertPathValidator and
* your list of trusted roots.
*/
}
};
编辑:
Ryan 是对的,我忘了解释如何将新根添加到现有根中。假设您当前的受信任根 KeyStore 源自 cacerts(JDK 附带的“Java 默认信任库”,位于 jre/lib/security 下)。我假设您使用 KeyStore#load(InputStream, char[]) 加载了该密钥库(它是 JKS 格式)。
KeyStore ks = KeyStore.getInstance("JKS");
FileInputStream in = new FileInputStream("<path to cacerts"");
ks.load(in, "changeit".toCharArray);
cacerts 的默认密码是“changeit”,如果您还没有更改的话。
然后您可以使用KeyStore#setEntry 添加其他受信任的根。您可以省略 ProtectionParameter(即 null),KeyStore.Entry 将是一个 TrustedCertificateEntry,它将新根作为其构造函数的参数。
KeyStore.Entry newEntry = new KeyStore.TrustedCertificateEntry(newRoot);
ks.setEntry("someAlias", newEntry, null);
如果您想在某个时候保留更改后的信任存储,您可以使用KeyStore#store(OutputStream, char[] 实现此目的。