英文:
HttpClient takes always the first certificate entry form KeyStore
问题
我有两个不同的密钥库service1.jks
和service2.jks
,分别对应于两个不同的服务(尽管它们具有相同的根证书)。这是我的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();
}
我需要在项目中只使用一个共享的密钥库。因此,我将service1.jks
和service2.jks
合并为一个常用密钥库common.jks
:
cp service2.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 common.jks
密钥库类型: JKS
密钥库提供方: SUN
您的密钥库中包含 2 个条目
service1-alias, 8 сент. 2020 г., PrivateKeyEntry,
证书指纹 (SHA-256):
....
service2-alias, 8 сент. 2020 г., PrivateKeyEntry,
证书指纹 (SHA-256):
...
然后,问题出现在我的 HttpClient
中,现在它只与第一个 service1
成功通信,而对 service2
的请求变为未经授权。对我来说,似乎 HttpClient
现在只使用了 common.jks
中的第一个条目。如何使 HttpClient
使用请求的正确别名?
英文:
I have two different keyStores service1.jks
and sevice2.jks
for two different services correspondingly (but they have the same RootSertificate though). Here is my httpClient
which works successfully with the two services:
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();
}
I have a need to use only one shared keyStore in my project. So I merged service1.jks
and sevice2.jks
into one common keyStore common.jks
:
cp sevice2.jks common.jks
keytool -importkeystore -srckeystore service1.jks -srcstoretype jks -srcstorepass changeit -destkeystore common.jks -deststoretype jks -deststorepass changeit
So common.jks
has two items:
$ 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, 8 сент. 2020 г., PrivateKeyEntry,
Certificate fingerprint (SHA-256):
...
Then it turned out that my HttpClient
now works successfully only with the first service1
, while requests to service2
became unauthorized. It seems for me that my HttpClient
takes now only the first entry form common.jks
. How to make HttpClient
to use the correct alias for the request?
答案1
得分: 2
我相信这是默认行为。在 SSLContextBuilder 的 Javadocs 中有一个 注释:
> 请注意:SSLContext.init(KeyManager[],TrustManager[],SecureRandom) 的默认 Oracle JSSE 实现接受多个密钥和信任管理器,但只会使用第一个匹配的类型。例如,请参阅:SSLContext.html#init
许多 Java 库和框架都存在这个问题 - 证书可以存储在带有别名的密钥库中,原则上,如果应用程序必须呈现证书,它可以选择使用哪个别名。然而,执行此操作的功能通常会从库中省略,假设应用程序永远不需要使用多个密钥库。
英文:
I believe this is the default behaviour. There's a note in the Javadocs for SSLContextBuilder:
> Please note: the default Oracle JSSE implementation of
> SSLContext.init(KeyManager[], TrustManager[], SecureRandom) accepts
> multiple key and trust managers, however only only first matching type
> is ever used. See for example: SSLContext.html#init
Many Java libraries and frameworks have this problem -- certificates can be stored in a keystore with a alias and, in principle, an application can select which alias to use if it has to present a certificate. However, facilities to do this are often ommited from libraries, on the assumption that an application will never need to use more than a single keystore.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论