Generate SSL Certificate using keytool provide in jdk
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.
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
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 crea开发者_高级运维te 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
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
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()
).
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
.
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.
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).
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.
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.
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).
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.
Check how your API allows you to define where your trusted certificates are.
精彩评论