问题描述
我分别为两个不同的服务有两个不同的密钥库service1.jks
和sevice2.jks
(但是它们具有相同的RootSertificate)。这是我的httpClient
,可成功与两种服务一起使用:
public HttpClient getHttpClient(String filePath,String password) {
KeyStore keyStore = KeyStore.getInstance(new File(filePath),password.tochararray());
SSLContext sslContext = new SSLContextBuilder()
.loadKeyMaterial(keyStore,password.tochararray())
.build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,(hostname,session) -> true);
return HttpClients.custom()
.setSSLSocketFactory(socketFactory)
.build();
}
我只需要在项目中使用一个共享的keyStore。因此,我将service1.jks
和sevice2.jks
合并到一个公用keyStore common.jks
中:
cp sevice2.jks common.jks
keytool -importkeystore -srckeystore service1.jks -srcstoretype jks -srcstorepass changeit -destkeystore common.jks -deststoretype jks -deststorepass changeit
所以common.jks
有两项:
$ keytool -list -storepass changeit -keystore server.keystore.jks
Keystore type: JKS
Keystore provider: SUN
Your keystore contains 2 entries
service1-alias,8 сент. 2020 г.,PrivateKeyEntry,Certificate fingerprint (SHA-256):
....
service2-alias,Certificate fingerprint (SHA-256):
...
然后事实证明,我的HttpClient
现在只能与第一个service1
一起成功使用,而对service2
的请求却被未经授权。在我看来,我的HttpClient
现在仅采用第一个输入形式common.jks
。如何使HttpClient
为请求使用正确的别名?
解决方法
我相信这是默认行为。 Javadocs for SSLContextBuilder中有一个note:
请注意:默认的Oracle JSSE实现 SSLContext.init(KeyManager [],TrustManager [],SecureRandom)接受 多个密钥和信任管理器,但是只有第一个匹配类型 曾经被使用过。例如,请参阅:SSLContext.html#init
许多Java库和框架都存在此问题-证书可以使用别名存储在密钥库中,并且原则上,如果必须提供证书,则应用程序可以选择要使用的别名。但是,假设应用程序永远不需要使用多个密钥库,就常常会从库中忽略执行此操作的功能。