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

时间:2014-02-11 08:15:26

标签: java ssl certificate

我希望我的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. 如果不可能我应该如何编写我的代码(我要求算法),以便它在第一次搜索后不会抛出异常而失败?

  3. P.S。 :我对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();
    }
    

3 个答案:

答案 0 :(得分:9)

javax.net.ssl.trustStore不能有多条路径。

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

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

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

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


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

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

答案 1 :(得分:2)

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

答案 2 :(得分:0)

虽然有些晚,但我想对MarquisDon't You Worry Child提供的答案进行评论。实际上,这几乎是不可能的,实际上,通过许多自定义代码,这是有可能实现的,我们已经在以下类似问题的答案中看到了它:Using a custom truststore in java as well as the default one

在遇到多个项目的相同挑战之后,我认为创建一个图书馆并使其公开提供以回馈社区非常方便。请在这里看看:Github - SSLContext-Kickstart

您的用例将用于加载jdk信任库和您自己的信任库:

import nl.altindag.sslcontext.SSLFactory;

import javax.net.ssl.SSLContext;
import java.security.cert.X509Certificate;
import java.util.List;

public class App {

    public static void main(String[] args) {
        String trustStorePath = ...;
        char[] password = "password".toCharArray();


        SSLFactory sslFactory = SSLFactory.builder()
                .withDefaultTrustMaterial()
                .withTrustMaterial(trustStorePath, password)
                .build();

        SSLContext sslContext = sslFactory.getSslContext();
        List<X509Certificate> trustedCertificates = sslFactory.getTrustedCertificates();
    }

}