如何在新的(未弃用的)SSLSocketFactory 中加载私钥密码?

Dra*_*max 2 java ssl keystore sslsocketfactory keystore-access

我当前的 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);
Run Code Online (Sandbox Code Playgroud)

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

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();
Run Code Online (Sandbox Code Playgroud)
  • 我认为问题在于我没有.custom()新库下的上下文方法。
    什么用于新的 SSLSocketFactory?
  • 是不是 JKS 密钥库没有存储在其中的私钥的内部密码(直到现在我只使用 PKCS,不熟悉 JKS 格式),这就是为什么我看不到私钥密码被引用的原因到?

dav*_*085 5

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

注意:该API允许你使用从Storepass用于一个关键通过不同的,但是其他的软件,使用它你可能想交换或共享PKCS12文件(如Windows,MacOSX的,OpenSSL的,我觉得NSS)并没有支持这一点,并尽量避免此类问题 Java 的命令行keytool不会将 keypass 设置为与 PKCS12 的storepass 不同。

什么用于新的 SSLSocketFactory?

SSLContext.getSocketFactory()——正如你发布的那样。事实上,这实际上是您之前的,已弃用的org.apache.http.conn.ssl.SSLSocketFactory.SSLSocketFactory(SSLContext)在内部所做的,除了它也默认为 HostNameVerifier。

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

不; JKS店做有独立的storepass,也关键通过,这将在你张贴如果我上面描述已更正的代码中使用-虽然专用密钥加密JKS使用的keypass比一般在PKCS12使用的一个弱。并且由于 JKS 文件无论如何都不能与其他软件互操作,因此keytool确实支持将 keypass 与 storepass 不同。事实上keytool(和 JCA 通常)支持在一个 JKS 存储中为不同的私钥使用不同的 keypass 值,但是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();
Run Code Online (Sandbox Code Playgroud)