java SSL客户端应用程序如何支持多个TrustStores
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3674849/
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
How support multiple TrustStores in java SSL client application
提问by user443180
In our java application we need to communicate with a list of servers on SSL using https protocol. The list of servers to communicate will change at runtime. Initially we do not have any of the server's certificate. At runtime, we will obtain a new server's certificate and add the public key certificate into a truststore; and any new https connection with the server should use the updated trust store.
在我们的 java 应用程序中,我们需要使用 https 协议与 SSL 上的服务器列表进行通信。要通信的服务器列表将在运行时更改。最初我们没有任何服务器的证书。在运行时,我们将获取一个新的服务器证书并将公钥证书添加到信任库中;并且与服务器的任何新 https 连接都应使用更新后的信任存储。
We are thinking that we should use two trust stores, one cacerts(default one shipped with jre) and other containing certificates of the servers that we add/remove dynamically in a list. This will make sure that we do not modify the default TrustStore(cacerts) of java.
我们认为我们应该使用两个信任存储,一个 cacerts(默认一个与 jre 一起提供)和另一个包含我们在列表中动态添加/删除的服务器的证书。这将确保我们不会修改 java 的默认 TrustStore(cacerts)。
Please suggest how this can be achieved. Also, is there any way to use a specific trust store only for a particular thread in java, so that other(existing and new) threads should still use the default java trueststore(cacerts), and one specific thread will use the particular truststore for the server.
请建议如何实现这一点。此外,是否有任何方法可以仅对 java 中的特定线程使用特定的信任库,以便其他(现有的和新的)线程仍应使用默认的 java trueststore(cacerts),并且一个特定的线程将使用特定的信任库服务器。
Thank you, Deepak
谢谢你,迪帕克
回答by Bruno
If you want to import certificate dynamically, you may need to use a custom x509TrustManager
. This is done when configuring the SSLContext
, which is itself used to create the SSLSocketFactory
or SSLEngine
.
如果要动态导入证书,可能需要使用自定义x509TrustManager
. 这是在配置 时完成的SSLContext
,它本身用于创建SSLSocketFactory
或SSLEngine
。
jSSLutilsis a library that lets you wrap existing trust managers and customize certain settings. You don't need it, but it may help.
jSSLutils是一个库,可让您包装现有的信任管理器并自定义某些设置。你不需要它,但它可能会有所帮助。
This would go along these lines:
这将沿着以下路线进行:
PKIXSSLContextFactory sslContextFactory = new PKIXSSLContextFactory();
sslContextFactory.setTrustManagerWrapper(new X509TrustManagerWrapper() {
@Override
public X509TrustManager wrapTrustManager(final X509TrustManager origManager) {
return new X509TrustManager() {
@Override
public X509Certificate[] getAcceptedIssuers() {
return origManager.getAcceptedIssuers();
}
@Override
public void checkServerTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
try {
// This will call the default trust manager
// which will throw an exception if it doesn't know the certificate
origManager.checkServerTrusted(chain, authType);
} catch (CertificateException e) {
// If it throws an exception, check what this exception is
// the server certificate is in chain[0], you could
// implement a callback to the user to accept/refuse
}
}
@Override
public void checkClientTrusted(X509Certificate[] chain,
String authType)
throws CertificateException {
origManager.checkClientTrusted(chain, authType);
}
};
}
});
SSLContext sslContext = sslContextFactory.buildSSLContext();
(The (PKIX)SSLContextFactory
and X509TrustManagerWrapper
come from jSSLutils, but the rest is available with the J2SE/J2EE.)
((PKIX)SSLContextFactory
和X509TrustManagerWrapper
来自 jSSLutils,但其余的可用于 J2SE/J2EE。)
There are a few CertificateException
sthat you may want to catch (see subclasses).
If you make a callback to the user, it's possible that the SSL/TLS connection will fail the first time because of a time-out on the SSL/TLS handshake (if the callback takes too long to be replied to.)
有几个CertificateException
小号,你可能要赶上(见子类)。如果您对用户进行回调,则 SSL/TLS 连接第一次可能会失败,因为 SSL/TLS 握手超时(如果回调花费的时间太长而无法回复。)
You could then use this SSLContext
as your default using SSLContext.setSSLContext(...)
(from Java 6), but that's not necessarily a good idea. If you can, pass the SSLContext
to the library that makes the SSL/TLS connection. How this is done varies, but Apache HTTP Client 4.x, for example, has multiple options to configure its SSL settings, one of them being by passing KeyStore
s, another one being by passing an SSLContext
.
然后您可以将其SSLContext
用作默认使用SSLContext.setSSLContext(...)
(来自 Java 6),但这不一定是一个好主意。如果可以,请将 传递SSLContext
给进行 SSL/TLS 连接的库。这是如何完成的,但例如,Apache HTTP Client 4.x 有多个选项来配置其 SSL 设置,其中之一是通过传递KeyStore
s,另一个是通过传递SSLContext
.
You could also to something per thread instead of per object that's going to connect (library dependent), by checking the current thread within the X509TrustManager
: this would probably make things a bit more complex in terms of synchronization and thread management/"awareness" by the trust manager.
您还可以通过检查以下内容中的当前线程来为每个线程而不是每个将要连接的对象(库相关)X509TrustManager
进行某些操作:这可能会使事情在同步和线程管理/“意识”方面变得更加复杂信托经理。
回答by William Crighton
This question is so old that I have my doubts my bit will help anyone but here goes...
这个问题太老了,我怀疑我的一点点会帮助任何人,但这里是......
If you want to solve the OP's (original poster) problem without resorting to code changes you can configure your JVM (I only tested with Tomcat) to support the OP's desired config:
如果您想在不求助于代码更改的情况下解决 OP(原始海报)问题,您可以配置您的 JVM(我只用 Tomcat 测试过)以支持 OP 所需的配置:
- leave the 'packaged' JDK cacerts file alone
- import your certs into a separate file and have your JAVA apps 'trust' them
- 单独留下“打包”的 JDK cacerts 文件
- 将您的证书导入一个单独的文件,并让您的 JAVA 应用程序“信任”它们
I used to just import my additional cert into a separate file and then reference it in my JVM startup with the parameter -Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/jssecacerts
with great success but I guess the recent (somewhat) JAVA security problems changed an automated inclusion of the cacerts file distributed with the SDK.
我曾经只是将我的附加证书导入到一个单独的文件中,然后在我的 JVM 启动中使用参数引用它-Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/jssecacerts
并取得了巨大成功,但我猜最近(有些)JAVA 安全问题改变了与 SDK 一起分发的 cacerts 文件的自动包含。
So I found a nifty solution using intel from this post and the these pages (with some minor changes):
所以我从这篇文章和这些页面中找到了一个使用英特尔的漂亮解决方案(有一些小改动):
- http://www.coderanch.com/t/529157/Tomcat/Configure-Tomcat-trust-store-cacerts
- http://andyarismendi.blogspot.com/2012/01/changing-tomcats-ca-trust-keystore-file.html
- http://www.coderanch.com/t/529157/Tomcat/Configure-Tomcat-trust-store-cacerts
- http://andyarismendi.blogspot.com/2012/01/changed-tomcats-ca-trust-keystore-file.html
What I used to do:
我曾经做过的事情:
- set the JVM trustStore parameter to my separate keystore file (that I'd import additional certs into) as follows
- 将 JVM trustStore 参数设置为我单独的密钥库文件(我会将其他证书导入其中),如下所示
What I do Now:
我现在应该做什么:
- Set the trustStore parameter to the 'packaged' cacerts file
- Set the keyStore parameter to my 'additional certs' file
- Set the keyStorePassword parameter to my keyStore's password (default is changeit)
- 将 trustStore 参数设置为“打包”的 cacerts 文件
- 将 keyStore 参数设置为我的“附加证书”文件
- 将 keyStorePassword 参数设置为我的 keyStore 的密码(默认为 changeit)
What it looks like:
它的样子:
-Djavax.net.ssl.trustStore=$JAVA_HOME/jre/lib/security/cacerts \
-Djavax.net.ssl.keyStore=$JAVA_HOME/jre/lib/security/jssecacerts \
-Djavax.net.ssl.keyStorePassword="changeit" \
Hope this is helpful to someone. I'm not 100% that you need to specify the keyStore password since you don't with the trustStore, but it works when you do.
希望这对某人有帮助。我不是 100% 您需要指定 keyStore 密码,因为您没有使用 trustStore,但是当您这样做时它可以工作。