如何将多个信任库路径添加到“java.net.ssl.trustStore”?

我希望我的Java代码在一个密钥库中搜索服务器的CA证书…如果它无法找到特定的证书(我认为只有当我尝试通过LDAP连接到Directory Server时才会知道),它应该是在另一个密钥库中查找证书,我知道它的路径。

我试过这个:

System.setProperty("javax.net.ssl.trustStore", System.getProperty("java.home") + "/lib/security/cacerts" + System.getProperty("path.separator") + path/to/second/keystore);

但它似乎没有用。

只添加一个路径(其中任何一个)都可以工作,即如果找到证书就会像魅力一样运行,否则就会失败。

所以我的问题是:

  1. 是否有方法将多堆密钥库路径添加到javax.net.ssl.trustStore?

  2. 如果不可能我应该如何编写我的代码(我要求算法),以便它在第一次搜索后不会抛出exception而失败?

PS:我对Java不太熟悉。

以下是我的代码的相关部分:

 if(useSSL) { try { SSLContext se = SSLContext.getInstance("TLS"); Security.addProvider(se.getProvider()); } catch(NoSuchAlgorithmException e) { } System.setProperty("javax.net.ssl.trustStore", System.getProperty("java.home") + "/lib/security/cacerts"); com.org.ldap.LDAPSocketFactory ssf = new LDAPJSSESecureSocketFactory(); LDAPConnection.setSocketFactory(ssf); } try { lc = new LDAPConnection(); lc.connect( ldapServer, ldapPort); lc.bind( ldapVersion, ldapUser, (userInfo[1]).getBytes() ); } catch (LDAPException le) { le.printStackTrace(); } 

您不能拥有javax.net.ssl.trustStore多个路径。

最简单的方法是制作JRE cacerts的本地副本,并将证书从其他商店导入其中(有效地合并它们)。 (参见keytool -importkeystore 。)

否则,如果您事先知道所有LDAP连接将使用第二个密钥库(并且您还希望能够将默认信任库用于其他非相关连接),则只能为该SSLSocketFactory配置该信任存储。 我不熟悉com.org.ldap.LDAPSocketFactory ,但它可能有一个选项可以这样做。 (否则,您可以创建使用第二个信任库初始化的自定义SSLContext并获取SSLSocketFactory ,如本答案中所述 )。

另一种更复杂的方法是创建一个自定义X509TrustManager ,它包装默认信任管理器,捕获其exception并再次尝试使用您的第二个存储初始化的另一个信任管理器。 这是可行的,但如果信任管理员都不接受您的证书,您需要确保它仍然会抛出exception(否则会出现安全漏洞)。 如果您不熟悉JSSE API(或Java),那么它可能不是最佳选择。

另外,在代码中使用System.setProperty("javax.net.ssl.trustStore", ...)时要小心:它是初始化默认SSLContext的读取,但默认SSLContext只初始化一次,第一次需要它。 之后设置此系统属性将不起作用(当然,除非其他库中的其他类也依赖于此值)。


目前还不清楚你要用这个来实现什么,因为你总是会成功地添加一个已经存在的安全提供者:

  try { SSLContext se = SSLContext.getInstance("TLS"); Security.addProvider(se.getProvider()); } catch(NoSuchAlgorithmException e) { } 

不,只需将所有证书从一个信任库导入另一个信任库,然后使用第二个。