HttpClient 始终采用第一个证书条目形式 KeyStore

HttpClient takes always the first certificate entry form KeyStore

我有两个不同的 keyStores service1.jkssevice2.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();
  }

我需要在我的项目中只使用一个共享密钥库。所以我将 service1.jkssevice2.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, 8 сент. 2020 г., PrivateKeyEntry,
Certificate fingerprint (SHA-256): 
...

然后我的 HttpClient 现在只在第一个 service1 上成功运行,而对 service2 的请求变得未经授权。在我看来,我的 HttpClient 现在只需要第一个条目表格 common.jks。如何使 HttpClient 为请求使用正确的别名?

我相信这是默认行为。在 SSLContextBuilder 的 Java 文档中有一个 note

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

许多 Java 库和框架都有这个问题——证书可以用别名存储在密钥库中,原则上,应用程序可以 select 如果必须使用哪个别名出示证书。但是,库通常忽略了执行此操作的工具,假设应用程序永远不需要使用多个密钥库。