2

我当前的 TCP 客户端正在使用org.apache.http.conn.ssl.SSLSocketFactory
我正在迁移到的构建套接字import javax.net.ssl.SSLSocketFactory; 但是,我不确定如何加载存储在我已经拥有的 .p12 文件中的客户端证书的私钥,作为新 SSLSocketFactory 的上下文?

这是我现有的代码,使用已弃用的 SSLSocketFactory:

import org.apache.http.ssl.SSLContexts;
import org.apache.http.conn.ssl.SSLSocketFactory;

String ksPassphrase = "myKSpass";
String pkPassphrase = "myPKpass";
// Get a keystore instance of type PKCS12:
KeyStore keystore = KeyStore.getInstance("PKCS12");
// Load keystore file and password:
keystore.load(new FileInputStream("myFile.p12"), ksPassphrase.toCharArray());
// Create HTTPS connection socket factory context:
SSLContext context = SSLContexts.custom()
    .loadKeyMaterial(keystore, pkPassphrase.toCharArray())
    .build();

SSLSocketFactory sslScktFactory = new SSLSocketFactory(context);

这是我可以从文档中管理的最佳代码:

import javax.net.ssl.*;

// not sure if this is the pass to KS or private key or, somehow both?
String passphrase = "myPassphrase" 

SSLContext context = SSLContext.getInstance("TLS");
KeyManagerFactory keyMngFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("JKS");

keyStore.load(new FileInputStream("myFile.jks"), passphrase.toCharArray());
keyMngFactory.init(keyStore, passphrase);
context.init(keyMngFactory.getKeyManagers(), null, null);

SSLSocketFactory sslScktFactory = context.getSocketFactory();
  • 我认为问题在于我没有.custom()新库下的上下文方法。
    新的 SSLSocketFactory 使用什么?
  • 是不是 JKS 密钥库没有存储在其中的私钥的内部密码(我直到现在才使用 PKCS,不熟悉 JKS 格式),这就是为什么我看不到私钥密码被引用的原因至?
4

1 回答 1

6

您传递给KeyStore.load(InputStream,char[])的密码是商店密码;您传递给的密码KeyManagerFactory.init(KeyStore,char[])是私钥密码(“单数”;如果有多个密钥,则所有密钥必须相同)并注意它char[]不是String——您的编译器(或 IDE)应该告诉您这一点。KeyStore.getInstance("PKCS12")如果您想继续使用现有的(或任何其他/新的)PKCS12 文件,您确实需要更改要使用的新代码。

请注意,API 允许您使用不同于 storepass 的密钥密码,但您可能希望与之交换或共享 PKCS12 文件的其他软件(如 Windows、MacOSX、OpenSSL,我认为是 NSS)不支持此功能,并尽量避免此类问题 Java 的命令行不会为 PKCS12keytool设置不同于 storepass 的 keypass 。

新的 SSLSocketFactory 使用什么?

SSLContext.getSocketFactory()- 与您发布的完全一样。实际上,这实际上是您以前org.apache.http.conn.ssl.SSLSocketFactory.SSLSocketFactory(SSLContext)在内部不推荐使用的,除了它还默认 HostNameVerifier。

是不是 JKS 密钥库没有存储在其中的私钥的内部密码(我直到现在才使用 PKCS,不熟悉 JKS 格式),这就是为什么我看不到私钥密码被引用的原因至?

不; JKS 商店确实有单独的 storepass 和 keypass,如果按照我上面的描述进行更正,它们将在您发布的代码中使用——尽管 JKS 使用 keypass 的私钥加密比 PKCS12 中通常使用的加密要弱而且由于 JKS 文件无论如何都不能与其他软件互操作,因此keytool确实支持 keypass 与 storepass 不同。事实上keytool(通常是 JCA)支持在一个 JKS 存储中为不同的私钥设置不同的密钥传递值,但是KeyManagerFactory(对于 SSL/TLS 即 JSSE)不支持这一点,Apache 也不支持(除了添加/包装密钥选择策略之外在下面使用 JSSE)。

(OP)编辑:这是您的建议产生的一些经过测试的工作代码:

// Consider having both the same, for compatibility with Windows/MacOSX/OpenSSL/etc:
String ksPassphrase = "myKSpass";
String pkPassphrase = "myPKpass";

SSLContext context = SSLContext.getInstance("TLS");
KeyManagerFactory keyMngFactory = KeyManagerFactory.getInstance("SunX509");
KeyStore keyStore = KeyStore.getInstance("PKCS12");

keyStore.load(new FileInputStream("myFile.p12"), 
ksPassphrase.toCharArray());
keyMngFactory.init(keyStore, pkPassphrase.toCharArray());
context.init(keyMngFactory.getKeyManagers(), null, null);

SSLSocketFactory sslScktFactory = context.getSocketFactory();
于 2019-11-14T20:52:48.687 回答