views:

77

answers:

3

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 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

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

A: 

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.

EJP
A: 

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.

Hila
A: 

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).

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).

Bruno
Ohh great it worked fine. Thanks dude..
ganuke