以编程方式访问 java 密钥库以创建 SSLSocketFactory
Posted
技术标签:
【中文标题】以编程方式访问 java 密钥库以创建 SSLSocketFactory【英文标题】:Access java keystore programmatically to create SSLSocketFactory 【发布时间】:2014-01-27 04:09:58 【问题描述】:我正在与启用 ssl 的服务器建立 SSL 连接。我的硬件文件系统 java 密钥库中有一个 cacerts 文件,我使用 keytool 从中提取了证书,并且我正在提供此证书文件以创建 SSLSocketfactory 以建立ssl 连接,与下面的代码 sn-p 配合得很好。
我想知道如何直接访问 cacerts (java keystore) 文件,然后选择证书并建立 ssl 连接。现在,我正在使用我的 jar 文件将提取的证书打包到类路径中,这不是一个好习惯,因为我希望从密钥库中加载它。
下面是我目前如何创建 SSLSocketFactory 的工作代码 sn-p。
private SSLSocketFactory createSSLFactory()
KeyStore keyStore = null;
TrustManagerFactory tmf = null;
SSLContext ctx = null;
try
keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream is = null;
is = SSLConnection.class.getResourceAsStream("/" + "my-keystore");
keyStore.load(is, "changeit".toCharArray());
tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(keyStore);
ctx = SSLContext.getInstance("TLSv1");
ctx.init(null, tmf.getTrustManagers(), null);
SSLSocketFactory factory = ctx.getSocketFactory();
return factory;
catch (Exception e)
// exception handling
return null;
【问题讨论】:
为什么?您甚至不需要此代码,更不用说更多代码了。只需设置系统属性即可。 会尝试回发,只是好奇。如果通过系统属性设置密钥库路径,它会像那样遍历密钥库并为服务器选择正确的证书吗? 你有它回到前面。它遍历信任库以查找 trusted 证书;在 SSL 握手的第一条消息中将这些subjectDNs
作为受信任的 CA 发送到服务器;服务器发回应该由这些 CA 之一签名的证书;然后客户端在密钥库中检查。没有“为服务器选择正确的证书”的问题,除非您仍在谈论客户端身份验证。
【参考方案1】:
在私钥和认证证书的情况下,将 KeyStore 嵌入到 JAR 文件中没有任何意义。客户端证书应该唯一标识客户端。它是主机的属性,而不是 JAR 文件,可以无限复制。允许多个客户端使用相同的客户端证书是没有意义的。这是对 PKI 的滥用。
【讨论】:
我的错误,它不是客户端身份验证,没有客户端到服务器的唯一标识。我将编辑问题。它只是建立到服务器的ssl。服务器的公钥给出连接到它。 这仍然是不好的做法。您应该使用 JDK 附带的信任库。如果您这样做是因为您的服务器使用的是自签名证书,那么正确的解决方案是不要这样做。得到它的签名。你会比在这里花的钱多。【参考方案2】:您可以将密钥库(和信任库)作为系统属性传递给 JVM。见这里:https://***.com/a/882479/131929
-Djavax.net.ssl.keyStoreType=pkcs12
-Djavax.net.ssl.trustStoreType=jks
-Djavax.net.ssl.keyStore=clientcertificate.p12
-Djavax.net.ssl.trustStore=gridserver.keystore
-Djavax.net.debug=ssl # very verbose debug
-Djavax.net.ssl.keyStorePassword=$PASS
-Djavax.net.ssl.trustStorePassword=$PASS
那你就可以了
URL url = new URL("https://someurl");
HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
InputStream inputstream = conn.getInputStream();
【讨论】:
您甚至不需要获取SSLSocketFactory
并将其设置为默认值。默认值已经是默认值了。正如 OP 现在所说他不需要客户端身份验证,他不需要 keyStore/keyStorePassword,
只是 trustStore.
trustStore 它是,与 trustStore 和 keystore 混淆了。做了一些学习,一切顺利。
@EJP - 嗯,当然是的,抱歉,我混合了我拥有的两个代码示例(现已修复)。我也认为OP的问题很奇怪。从问题直接回答。如果问题是“错误的”,那会让你无处可去……【参考方案3】:
您需要添加信任管理器:
SSLSocketFactory factory = null;
try
SSLContext ctx;
KeyManagerFactory kmf;
TrustManagerFactory tmf;
KeyStore ks;
char[] passphrase = "passphrase".toCharArray();
ctx = SSLContext.getInstance("TLS");
kmf = KeyManagerFactory.getInstance("SunX509");
tmf = TrustManagerFactory.getInstance("SunX509");
ks = KeyStore.getInstance("JKS");
ks.load(new FileInputStream("testkeys"), passphrase);
kmf.init(ks, passphrase);
tmf.init(ks);
ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
factory = ctx.getSocketFactory();
catch (Exception e)
throw new IOException(e.getMessage());
SSLSocket socket = (SSLSocket)factory.createSocket(host, port);
【讨论】:
以上是关于以编程方式访问 java 密钥库以创建 SSLSocketFactory的主要内容,如果未能解决你的问题,请参考以下文章