Java 密钥库可以导入 OpenSSL 生成的密钥对吗?

Posted

技术标签:

【中文标题】Java 密钥库可以导入 OpenSSL 生成的密钥对吗?【英文标题】:Can a Java key store import a key pair generated by OpenSSL? 【发布时间】:2011-02-10 17:55:19 【问题描述】:

我使用 openssl 生成一个认证密钥。这是我的命令:

openssl genrsa -des3 -out enc_key.pem 1024

我导出到 cer 文件,然后使用 java keytool 导入到 java keystore (jks)。

密钥库听起来不错。我可以从我的 java 应用程序中加载密钥库。

问题是当客户端连接到服务器时(这里是FTP服务器,不是web服务器,我用的是apache mina),出现异常:

javax.net.ssl.SSLHandshakeException:SSL 握手失败。 在 org.apache.mina.filter.ssl.SslFilter.messageReceived(SslFilter.java:433) 在 org.apache.mina.core.filterchain.DefaultIoFilterChain.callNextMessageReceived(DefaultIoFilterChain.java:434) 在 org.apache.mina.core.filterchain.DefaultIoFilterChain.access$5(DefaultIoFilterChain.java:429)

...

原因:javax.net.ssl.SSLHandshakeException:没有共同的密码套件 在 com.sun.net.ssl.internal.ssl.Handshaker.checkThrown(未知来源) 在 com.sun.net.ssl.internal.ssl.SSLEngineImpl.checkTaskThrown(未知来源) 在 com.sun.net.ssl.internal.ssl.SSLEngineImpl.writeAppRecord(未知来源) 在 com.sun.net.ssl.internal.ssl.SSLEngineImpl.wrap(未知来源) 在 javax.net.ssl.SSLEngine.wrap(Unknown Source)

...

原因:javax.net.ssl.SSLHandshakeException:没有共同的密码套件 在 com.sun.net.ssl.internal.ssl.Alerts.getSSLException(未知来源) 在 com.sun.net.ssl.internal.ssl.SSLEngineImpl.fatal(未知来源)

有几点想问:

    我使用 openssl 生成的证书密码是什么?我们怎么知道?也许通过命令行 openssl xxx? 我去http://java.sun.com/j2se/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#AppA。我将 SSL_RSA_xxx 放入启用的密码套件,但仍然无法工作(我放入 SSL_RSA 是因为 SSL 使用的是 ssl implisit 和 genrsa,只是我认为 genrsa 是生成 RSA)。对吗? 有人知道解决办法吗? 或者,任何人都知道如何从 openssl 命令行生成标准密钥库,直到可以在 java 应用程序中使用(当然,使用密码)。因为现在我可以从 openssl 生成证书并导出 keystore java,但我不知道我使用的密码是什么以及如何在 java 应用程序中使用。注意:如果密钥库是直接从 java 生成的,我可以运行。现在的问题是,java keytool 生成的密钥库是否来自 openssl 等认证(可能还有其他)。

任何帮助将不胜感激!谢谢

【问题讨论】:

【参考方案1】:

为什么要使用 OpenSSL 来生成密钥对?为什么不直接使用keytool

genrsa 工具只是生成一个私钥。您如何创建相应的证书?您如何将私钥导入 Java 密钥库? (我问,因为keytool 只能从现有密钥库中导入私钥,并且只能从 Java 6 开始。)

我怀疑您的问题是您的密钥库不包含密钥条目(私钥相应的证书)。当您使用keytool 列出密钥库内容时,有多少条目?它们是关键条目还是可信条目?


服务器需要访问私钥才能对自己进行身份验证。要导入私钥,请使用 Java 6 增强的keytool

使用 OpenSSL 创建密钥和证书后,使用 OpenSSL 创建 PKCS #12 密钥库:

openssl pkcs12 -export -in cert.pem -inkey key.pem > server.p12

然后将此存储转换为 Java 密钥存储:

keytool -importkeystore -srckeystore server.p12 -destkeystore server.jks -srcstoretype pkcs12

现在在启用 SSL 的服务器中使用 server.jks,其中包含证书私钥。

【讨论】:

基本上,我可以使用由 java keytool 生成的密钥库运行应用程序(请参阅我的问题点 4)(是的,就像你说的,它是正确的,我已经这样做了)。如果我直接从 java keytool 生成密钥库(jks),那么我的应用程序(FTPS 服务器)只使用该密钥库。没问题。您为什么使用 OpenSSL 生成密钥对的问题是因为当前客户端具有许可证认证(verisign),所以我必须先使用 openssl 进行测试。顺便说一句,keytool 可以从 cert x509 导入(通过执行命令:openssl req -x509 -key key.pem -in req.pem -out cert.pem -days 365) 从上面继续我已经将 openssl 生成的密钥导入到 java 密钥库 (jks) 并且 java 应用程序说密钥库已经有效(我尝试另一个密钥,java 可以验证其有效的密钥库或不是)。问题是当我通过密钥库(由从 openssl cert 导入的 java keytool 生成)运行应用程序时,应用程序会在上面抛出异常。密钥库包含一个密钥条目(它在 httpd ssl 中工作),当我执行 keytool list 时,该条目已经被信任。我执行此命令: keytool -import -v -trustcacerts -alias server-alias -file cert.pem -keystore cacerts.jks -keypass x -storepass x @Jef — 您正在尝试为服务器生成密钥库,对吗?服务器总是需要一个私钥。任何人都可以获得证书;它是公开的。但是没有私钥,他们就无法冒充服务器。按照上述步骤,与“cert.pem”一起使用的私钥(“key.pem”)永远不会导入到 Java 密钥存储中。如果您使用 Java 6,则可以将 OpenSSL 创建的 PKCS #12 密钥库(包括私钥)“导入”到“JKS”Java 密钥库中。否则,它将不起作用。 @Jef — 要完成这项工作,您必须使用 Java 6。以前的版本没有导入密钥存储功能。您不必使用 Java 6 运行或开发程序,但除非您编写一些自己的代码来管理密钥库,否则您将需要 Java 6 运行时来转换密钥库。 好吧,埃里克森,它有效。谢谢! java 5 做不到。 java 6可以做到这一点(你上面的命令)。对于替代方案(也许您也已经知道这一点),我尝试使用本指南在 java 5 中进行转换:agentbob.info/agentbob/79-AB.html

以上是关于Java 密钥库可以导入 OpenSSL 生成的密钥对吗?的主要内容,如果未能解决你的问题,请参考以下文章

openssl与java(读取加密码的密钥)

无法从 Java 读取 OpenSSL 生成的 ECDSA 密钥:InvalidKeySpecException

java编程之:生成rsa密钥

无法导入 .p12 密钥库

java - 如何在java中生成与openssl生成的相同类型的ecdsa密钥对?

使用openssl和java进行SM4密钥调试