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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21707894/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 10:11:50  来源:igfitidea点击:

How to add multiple truststore paths to “java.net.ssl.trustStore”?

javasslcertificate

提问by Don't You Worry Child

I want my Java Code to search for CA certificate of the server in one keystore... if it is unable to find the specific certificate (which I think will be known only when I try to connect via LDAP to Directory Server), it should look for the certificate in another keystore, whose path I know.

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

I tried this:

我试过这个:

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

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

But it didn't seem to work.

但它似乎没有用。

Adding only one path (either of them) works, i.e. it runs like charm if certificate is found and fails if not.

只添加一个路径(其中之一)有效,即如果找到证书,它就会像魅力一样运行,否则就会失败。

So my question is:

所以我的问题是:

  1. Is there a method to add multpile keystore paths to javax.net.ssl.trustStore?

  2. If it is not possible how should I write my code (I am asking for the algorithm) so that it just not throw Exception after first search itself and fail?

  1. 有没有一种方法可以将多个密钥库路径添加到 javax.net.ssl.trustStore?

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

P.S. : I am not much familiar with Java.

PS:我对Java不太熟悉。

Below is the relevant section of my code:

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

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();
}

回答by Bruno

You can't have multiple paths for javax.net.ssl.trustStore.

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

The easiest would be to make a local copy of the JRE's cacertsand import the certificates from your other store into it (effectively merging them). (See keytool -importkeystore.)

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

Otherwise, if you know in advance that all your LDAP connections will use your second keystore (and you also want to be able to use the default truststore for other, non-related connections), you could configure that trust store for that SSLSocketFactoryonly. I'm not familiar with com.org.ldap.LDAPSocketFactory, but it might have an option to do so. (Otherwise, you could create your custom SSLContextinitialised with your second truststore and get an SSLSocketFactory, as described in this answer).

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

Another, more complicated way, would be to create a custom X509TrustManagerthat wraps the default trust manager, catches its exceptions and tries again with another trust manager initialised using your second store. It's feasible, but you'd need to make sure it still throws the exception if neither trust managers accept your certificate (otherwise, there would be a security hole). If you're not familiar with the JSSE API (or Java altogether), it's probably not the best option.

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

In addition, be careful when you use System.setProperty("javax.net.ssl.trustStore", ...)in your code: it is what's read to initialise the default SSLContext, but the default SSLContextis only initialised once, the first time it's required. Setting this system property afterwards would have no effect (unless of course, other classes from other libraries also rely on this value).

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



It's also not clear what you're trying to achieve with this, since you'll always ever succeed to add a security provider that's already there:

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

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

回答by user207421

No, just import all the certificates from one truststore into the other, and use the second.

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