Java 使用 jdk 中提供的 keytool 生成 SSL 证书
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3797704/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Generate SSL Certificate using keytool provide in jdk
提问by nath
Keystore files I have used in my web application expired last week. I generated it long time ago. So I started generating new certificate using keytool. I used this certificate to connect a transaction server and the web server. I wanted to use self signed certificate for this application. I generate it using following command to generate self signed key for transaction server.
我在 Web 应用程序中使用的密钥库文件上周已过期。我很久以前生成的。所以我开始使用 keytool 生成新证书。我使用此证书连接事务服务器和 Web 服务器。我想为此应用程序使用自签名证书。我使用以下命令生成它来为交易服务器生成自签名密钥。
keytool -genkey -keystore keys/SvrKeyStore -keyalg rsa -validity 365 -alias Svr -storepass 123456 -keypass abcdefg -dname "CN=One1, OU=Development1, O=One, L=Bamba, S=Western Prov1, C=S1"
following commnad to generate keystore for web application
以下命令为 Web 应用程序生成密钥库
keytool -genkey -keystore keys/ClientKeyStore -keyalg rsa -validity 365 -alias Web -storepass 123456 -keypass abcdefg -dname "CN=One, OU=Development, O=One, L=Bamba, S=Western Prov, C=SL"
I used following code in the transaction server to create the socket connection
我在事务服务器中使用以下代码来创建套接字连接
String KEYSTORE = Config.KEYSTORE_FILE;//SvrKeyStore keystore file
char[] KEYSTOREPW = "123456".toCharArray();
char[] KEYPW = "abcdefg".toCharArray();
com.sun.net.ssl.TrustManagerFactory tmf;
boolean requireClientAuthentication;
java.security.Security.addProvider(new com.sun.net.ssl.internal.ssl.
Provider());
java.security.KeyStore keystore = java.security.KeyStore.getInstance(
"JKS");
keystore.load(new FileInputStream(KEYSTORE), KEYSTOREPW);
com.sun.net.ssl.KeyManagerFactory kmf = com.sun.net.ssl.
KeyManagerFactory.getInstance("SunX509");
kmf.init(keystore, KEYPW);
com.sun.net.ssl.SSLContext sslc = com.sun.net.ssl.SSLContext.
getInstance("SSLv3");
tmf = com.sun.net.ssl.TrustManagerFactory.getInstance("sunx509");
tmf.init(keystore);
sslc.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLServerSocketFactory ssf = sslc.getServerSocketFactory();
SSLServerSocket ssocket = (SSLServerSocket) ssf.createServerSocket(port);
ssocket.setNeedClientAuth(true);
But it gives following exception when I used it in my application and try to connect to the transaction server through web server
但是当我在我的应用程序中使用它并尝试通过 Web 服务器连接到事务服务器时,它给出了以下异常
javax.net.ssl.SSLException: Connection has been shutdown: javax.net.ssl.SSLHands
hakeException: java.security.cert.CertificateException: Untrusted Server Certifi
cate Chain
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.checkEOF(SSLSocketImpl.jav
a:1172)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:
65)
at net.schubart.fixme.internal.MessageInput.readExactly(MessageInput.jav
a:166)
at net.schubart.fixme.internal.MessageInput.readMessage(MessageInput.jav
a:78)
at cc.aot.itsWeb.ClientWriterThread.run(ClientWriterThread.java:241)
at java.lang.Thread.run(Thread.java:619)
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateEx
ception: Untrusted Server Certificate Chain
at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1
520)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:182)
at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:176)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(Clien
tHandshaker.java:975)
at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHa
ndshaker.java:123)
at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:5
11)
at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.jav
a:449)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.j
ava:817)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SS
LSocketImpl.java:1029)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.writeRecord(SSLSocketImpl.
java:621)
at com.sun.net.ssl.internal.ssl.AppOutputStream.write(AppOutputStream.ja
va:59)
at java.io.OutputStream.write(OutputStream.java:58)
Please can any one tell me where is the problem
请谁能告诉我问题出在哪里
采纳答案by Bruno
Firstly, avoid using the com.sun.net.ssl
packages and classes directly. The architecture of the JSSE is built so that you can use the factories and specify the providers later. Use javax.net.ssl.TrustManagerFactory
(same for KeyManagerFactory
and SSLContext
) instead. (I'd suggest using "PKIX"
instead of "SunX509"
for the trust manager algorithm, as it's normally the default with the Sun provider, or better, use TrustManagerFactory.getDefaultAlgorithm()
).
首先,避免com.sun.net.ssl
直接使用包和类。构建了 JSSE 的体系结构,以便您可以在以后使用工厂并指定提供者。改用javax.net.ssl.TrustManagerFactory
(与KeyManagerFactory
和相同SSLContext
)。(我建议使用"PKIX"
而不是"SunX509"
用于信任管理器算法,因为它通常是 Sun 提供者的默认设置,或者更好,使用TrustManagerFactory.getDefaultAlgorithm()
)。
Secondly, you don't need to set up a keymanager on the client side unless you're using client-certificate authentication.
其次,除非您使用客户端证书身份验证,否则您不需要在客户端设置密钥管理器。
Finally (and perhaps the most important), you need to export the self-signed certificate you've generated on the server side (only the certificate, not the private key) and import it into the keystore you use as a trust store on the client side.
最后(也许是最重要的),您需要导出您在服务器端生成的自签名证书(仅证书,而不是私钥)并将其导入您用作信任存储的密钥库中客户端。
When you generate the certificate, you should make sure you use CN=the.server.host.name
.
生成证书时,应确保使用CN=the.server.host.name
.
keytool -genkey -keystore server-keystore.jks -alias server_alias \
-dname "CN=the.server.host.name,OU=whateveryoulike" \
-keyalg "RSA" -sigalg "SHA1withRSA" -keysize 2048 -validity 365
keytool -export -keystore server-keystore.jks -alias server_alias -file server.crt
keytool -import -keystore client-truststore.jks -file server.crt
If you want to use client-certificate authentication, you need to repeat the operation by replacing server-keystore and client-truststore with client-keystore and server-truststore respectively.
如果要使用client-certificate认证,需要重复操作,将server-keystore和client-truststore分别替换为client-keystore和server-truststore。
In this case, server-keystore.jks
and server-truststore.jks
could be the same file, but you don't need to (same on the client side).
在这种情况下,server-keystore.jks
并且server-truststore.jks
可能是同一个文件,但您不需要(在客户端相同)。
回答by user207421
All you needed to do was keytool -selfcert - alias XXX -validity DDD where XXX is the same alias as before and DDD is the number of days before expiry, for the server cert, then export that cert and import into the client's truststore. Repeat in reverse for the client. You've left out the export/import part.
您需要做的就是 keytool -selfcert - alias XXX -validity DDD 其中 XXX 是与以前相同的别名,而 DDD 是到期前的天数,对于服务器证书,然后导出该证书并导入到客户端的信任库中。为客户反向重复。您已经遗漏了导出/导入部分。
However much of that code is now obsolete. You don't need to call addProvider(), and you can change com.sun.net.ssl to javax.net.ssl throughout the remainder.
然而,大部分代码现在已经过时了。您不需要调用 addProvider(),并且您可以在其余部分将 com.sun.net.ssl 更改为 javax.net.ssl。
回答by Hila
To understand this you have to understand how certificates work.
要理解这一点,您必须了解证书的工作原理。
Since anyone can create a certificate (like you did), it is not enough just to create it - certificates have to be trusted. A certificate is trusted only if it is signed by another certificate, which is trusted. On the top of the trust "food chain" there are several major CAs, to whom you can pay money to have your certificate "publicly trusted" (your computer comes with their certificates installed on it).
由于任何人都可以创建证书(就像您所做的那样),仅创建它是不够的 - 必须信任证书。仅当证书由另一个受信任的证书签名时,该证书才受信任。在信任“食物链”的顶端,有几个主要的 CA,您可以向它们支付费用以获得“公开信任”的证书(您的计算机上安装了他们的证书)。
Of course you don't have to pay to a CA in order your application, BUT you have to mimic this behavior. What you will probably have to do is export the server/client public key, and install it in some kind of trusted store.
当然,您不必为您的应用程序向 CA 付费,但您必须模仿这种行为。您可能需要做的是导出服务器/客户端公钥,并将其安装在某种受信任的商店中。
Check how your API allows you to define where your trusted certificates are.
检查您的 API 如何允许您定义可信证书的位置。