This discussion is archived
5 Replies Latest reply: Jul 9, 2010 5:16 AM by 843811 RSS

How to use Self Signed certificate with SSLServerSocket?

843811 Newbie
Currently Being Moderated
Hello to all.
I'm trying to build a simple client/server system wich uses SSLSocket to exchange data. (JavaSE 6)
The server must have it's own certificate, clients don't need one.

I started with this
http://java.sun.com/javase/6/docs/technotes/guides/security/jsse/JSSERefGuide.html#CreateKeystore
To generate key for the server and a self signed certificate.
To sum it up:
     Create a new keystore and self-signed certificate with corresponding public/private keys. 
keytool -genkeypair -alias mytest -keyalg RSA -validity 7 -keystore /scratch/stores/server.jks

     Export and examine the self-signed certificate.
keytool -export -alias mytest -keystore /scratch/stores/server.jks -rfc -file server.cer
 
     Import the certificate into a new truststore.
keytool -import -alias mytest -file server.cer -keystore /scratch/stores/client.jks
Then in my server code I do
System.setProperty("javax.net.ssl.keyStore", "/scratch/stores/server.jks");
System.setProperty("javax.net.ssl.keyStorePassword", "123456");

SSLServerSocketFactory sf = sslContext.getServerSocketFactory();
SSLServerSocket sslServerSocket = (SSLServerSocket)sf.createServerSocket( port );

Socket s = sslServerSocket.accept();
I am basically missing some point because I get a "javax.net.ssl.SSLException: No available certificate or key corresponds to the SSL cipher suites which are enabled." when I try to run the server.

Can it be a problem with the certificate? When using -validity <days> in keytool the certificate gets self-signed, so it should work if I'm not wrong.

I have also tried this solution
serverKeyStore = KeyStore.getInstance( "JKS" );
serverKeyStore.load( new FileInputStream("/scratch/stores/server.jks" ),
     "123456".toCharArray() );
tmf = TrustManagerFactory.getInstance( "SunX509" );
tmf.init( serverKeyStore );
               
sslContext = SSLContext.getInstance( "TLS" );
sslContext.init( null, tmf.getTrustManagers(),secureRandom );
               
SSLServerSocketFactory sf = sslContext.getServerSocketFactory();
SSLServerSocket ss = (SSLServerSocket)sf.createServerSocket( port );
and still it doesn't work.

So what am I missing?
  • 1. Re: How to use Self Signed certificate with SSLServerSocket?
    EJP Guru
    Currently Being Moderated
    You haven't told the client where its truststore is. See the document you cited.
  • 2. Re: How to use Self Signed certificate with SSLServerSocket?
    843811 Newbie
    Currently Being Moderated
    I forgot to write it, but I used the System.setProperty() on the client giving it its trustStore.
    Now I'm re-reading the whole page and trying to re-do all the process from the beginning.
    Still I can't get what I am missing or doing wrong.

    Thanks for your patience.
  • 3. Re: How to use Self Signed certificate with SSLServerSocket?
    843811 Newbie
    Currently Being Moderated
    So i created the keystore and truststore as mentioned in the tutorial.
    In my server now i do this setup
    private SSLServerSocket setupSSLServerSocket(){
              
              try {
                   SSLContext sslContext = SSLContext.getInstance( "TLS" );
                   
                   KeyManagerFactory km = KeyManagerFactory.getInstance("SunX509");
                   
                   KeyStore ks = KeyStore.getInstance("JKS");
                   
                   ks.load(new FileInputStream(_KEYSTORE), _KEYSTORE_PASSWORD.toCharArray());
                   
                   km.init(ks, _KEYSTORE_PASSWORD.toCharArray());
                   
                   TrustManagerFactory tm = TrustManagerFactory.getInstance("SunX509");
                   
                   tm.init(ks);
                   
                   sslContext.init(km.getKeyManagers(), tm.getTrustManagers(), null);
                   
                   SSLServerSocketFactory f = sslContext.getServerSocketFactory();
                   
                   SSLServerSocket ss = (SSLServerSocket) f.createServerSocket(_PORT);
                   
                   return ss;
                   
              } catch (UnrecoverableKeyException e) {
                   e.printStackTrace();
              } catch (KeyManagementException e) {
                   e.printStackTrace();
              } catch (NoSuchAlgorithmException e) {
                   e.printStackTrace();
              } catch (KeyStoreException e) {
                   e.printStackTrace();
              } catch (CertificateException e) {
                   e.printStackTrace();
              } catch (FileNotFoundException e) {
                   e.printStackTrace();
              } catch (IOException e) {
                   e.printStackTrace();
              }
              
              return null;
         }
    and start the server
    SSLServerSocket sslServerSocket = setupSSLServerSocket();
            
            for(String ciph : sslServerSocket.getEnabledCipherSuites())
                 System.out.println(ciph);
                 
              while (true) {
    
                   try {
                        Socket s = sslServerSocket.accept();
                        System.out.println( "Connection from "+s );
    
                        DataOutputStream dout = new DataOutputStream( s.getOutputStream() );
                        outputStreams.put( s, dout );
                        new ServerThread( this, s );
                        
                   } catch (Exception e) {
                        e.printStackTrace();
                   }
              }
    Upon starting I see a lot of supported cypher algorithms.
    In my client i simply load
              System.setProperty("javax.net.ssl.trustStore", "/scratch/stores/client.jks");
              System.setProperty("javax.net.ssl.trustStorePassword", "client");
              
              try {
                   
                   SSLSocketFactory socketFactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
                   SSLSocket sslSocket = (SSLSocket) socketFactory.createSocket(host, port);
                   
                   for(String ciph : sslSocket.getEnabledCipherSuites())
                 System.out.println(ciph);
                   //final String[] enabledCipherSuites = { "SSL_DH_anon_WITH_RC4_128_MD5" };
                   //sslSocket.setEnabledCipherSuites(enabledCipherSuites);
    
                   System.out.println( "connected to "+sslSocket );
    And see the same list of cypher algorithms.

    So why the println of the socket says
    connected to 542529[SSL_NULL_WITH_NULL_NULL: Socket[addr=localhost/127.0.0.1,port=5555,localport=34966]]
  • 4. Re: How to use Self Signed certificate with SSLServerSocket?
    EJP Guru
    Currently Being Moderated
                   km.init(ks, KEYSTOREPASSWORD.toCharArray());
    Here you are loading the KeyStore built from _KEYSTORE into the key manager. So this keystore must contain the server's private key and self-signed certificate.
                   tm.init(ks);
    Here you are loading the same keystore into the TrustManager. That doesn't make any sense. The TrustManager needs a truststore. e.g. the one distributed with the JDK, or your own if you have to put up with self-signed client certificates. As you aren't using client certificates you should delete this TrustManager and use the default one.

    No doubt you are making the same mistake on the client side. The client needs a truststore that trusts the server's keystore, i.e. that contains the exported/import server self-signed cert.
    So why the println of the socket says
    connected to 542529[SSL_NULL_WITH_NULL_NULL: Socket[addr=localhost/127.0.0.1,port=5555,localport=34966]]
    Because you haven't done the handshake yet. That happens on the first I/O.
  • 5. Re: How to use Self Signed certificate with SSLServerSocket?
    843811 Newbie
    Currently Being Moderated
    You were right. I corrected the mistakes in the server code, now it's
         private SSLServerSocket setupSSLServerSocket(){
              
              try {
                   SSLContext sslContext = SSLContext.getInstance( "TLS" );
                   
                   KeyManagerFactory km = KeyManagerFactory.getInstance("SunX509");
                   
                   KeyStore ks = KeyStore.getInstance("JKS");
                   
                   ks.load(new FileInputStream(_KEYSTORE), _KEYSTORE_PASSWORD.toCharArray());
                   
                   km.init(ks, _KEYSTORE_PASSWORD.toCharArray());
                   
                   /*
                    * Da usare con un truststore se serve autenticazione dei client
                    * TrustManagerFactory tm = TrustManagerFactory.getInstance("SunX509");
                   
                   tm.init(ks);*/
                   
                   sslContext.init(km.getKeyManagers(), null, null);
                   
                   SSLServerSocketFactory f = sslContext.getServerSocketFactory();
                   
                   SSLServerSocket ss = (SSLServerSocket) f.createServerSocket(_PORT);
                   
                   return ss;
                   
              } catch (UnrecoverableKeyException e) {
                   e.printStackTrace();
              } catch (KeyManagementException e) {
                   e.printStackTrace();
              } catch (NoSuchAlgorithmException e) {
                   e.printStackTrace();
              } catch (KeyStoreException e) {
                   e.printStackTrace();
              } catch (CertificateException e) {
                   e.printStackTrace();
              } catch (FileNotFoundException e) {
                   e.printStackTrace();
              } catch (IOException e) {
                   e.printStackTrace();
              }
              
              return null;
         }
    and on the client code
    private SSLSocket setupSSLClientSocket(){
         
         try {
              SSLContext sslContext = SSLContext.getInstance( "TLS" );
              
              /* SERVER
              KeyManagerFactory km = KeyManagerFactory.getInstance("SunX509");
              km.init(ks, _KEYSTORE_PASSWORD.toCharArray());
              */
              KeyStore clientks = KeyStore.getInstance("JKS");
              clientks.load(new FileInputStream(_TRUSTSTORE), _TRUSTSTORE_PASS.toCharArray());
    
              TrustManagerFactory tm = TrustManagerFactory.getInstance("SunX509");
              
              tm.init(clientks);
              
              sslContext.init(null, tm.getTrustManagers(), null);
              
              SSLSocketFactory f = sslContext.getSocketFactory();
              
              SSLSocket sslSocket = (SSLSocket) f.createSocket("localhost", _PORT);
              
              return sslSocket;
              
         } catch (KeyManagementException e) {
              e.printStackTrace();
         } catch (NoSuchAlgorithmException e) {
              e.printStackTrace();
         } catch (KeyStoreException e) {
              e.printStackTrace();
         } catch (CertificateException e) {
              e.printStackTrace();
         } catch (FileNotFoundException e) {
              e.printStackTrace();
         } catch (IOException e) {
              e.printStackTrace();
         }
         
         return null;
    }
    and added a System.out.println(sslSocket); after every incoming message (server side) and SSL is now fully working!

    So my mistakes were:
    [] Incorrect setup done by code
    [] Incorrect and insufficient println() of socket status

    Now that everything works, I've deleted all this manual setup and just use the system properties. (They MUST be set before getting the Factory)
    SERVER SIDE:
    System.setProperty("javax.net.ssl.keyStore", _KEYSTORE);
    System.setProperty("javax.net.ssl.keyStorePassword", KEYSTOREPASSWORD);

    SSLServerSocketFactory f = (SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
    SSLServerSocket sslServerSocket = (SSLServerSocket) f.createServerSocket(_PORT);

    CLIENT SIDE:
    System.setProperty("javax.net.ssl.trustStore", "/scratch/stores/client.jks");
    System.setProperty("javax.net.ssl.trustStorePassword", "client");

    SSLSocketFactory f = (SSLSocketFactory) SSLSocketFactory.getDefault();
    SSLSocket sslSocket = (SSLSocket) f.createSocket(_HOST, _PORT);

    And everything is working as expected. Thank you!

    I hope my code will help someone else in the future.