3

After reading through numerous answers concerning these topics, I have found myself completely unable to string together the pieces of the puzzle, I hope you will excuse me for this.

I am trying to change my simple socket connection in Java to use SSL. I would like both the server and client to authenticate themselves if possible, but only server authentication would be good start.

Currently, this is the extremely simple code on the server side:

    ServerSocket serverSocket = new ServerSocket(port);
    Socket socket = serverSocket.accept();

And this is the code on the client side:

    Socket socket = null;
    while (true) {
        try {
            socket = new Socket(ipAddress, port);
            break;
        } catch (Exception e) {}
    }

This works fine, but without SSL.

I have generated SSL certificates for the server and client using OpenSSL, ending up with:

  • A certificate for the server (PEM format)
  • A certificate for the client (PEM format)
  • A private key for the server (PEM format)
  • A private key for the client (PEM format)
  • A CA file (PEM, CER and CRT format)

From this I have used OpenSSL to create PKCS12 (.p12) keystores for both the client and the server, as follows

  • server.p12, made by doing openssl pkcs12 -export -in server-cert.pem -inkey server-private-key.pem -out server.p12
  • client.p12, made by doing openssl pkcs12 -export -in client-cert.pem -inkey client-private-key.pem -out client.p12

Then, I turned these into JKS keystores by using keytool (for the server, for example, the command was keytool -importkeystore -srckeystore server.p12 -srcstoretype PKCS12 -destkeystore server.jks -deststoretype JKS), resulting in two files named server.jks and client.jks.

I then use the following code as replacement for the previous server snippet:

    char[] keyStorePassword =  "JKSPassword".toCharArray();
    FileInputStream keyStoreFile = new FileInputStream("somepath/server.jks");
    KeyStore keyStore = KeyStore.getInstance("JKS");
    keyStore.load(keyStoreFile, keyStorePassword);
    KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    keyManagerFactory.init(keyStore, "PKCS12Password".toCharArray());
    SSLContext sslContext = SSLContext.getDefault();
    ServerSocket serverSocket = sslContext.getServerSocketFactory().createServerSocket(port);
    Socket socket = serverSocket.accept();

And the following code as replacement for the client snippet:

    Socket socket = null;
    while (true) {
        try {
            char[] keyStorePassword =  "JKSPassword".toCharArray();
            FileInputStream keyStoreFile = new FileInputStream("somepath/client.jks");
            KeyStore keyStore = KeyStore.getInstance("JKS");
            keyStore.load(keyStoreFile, keyStorePassword);
            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            keyManagerFactory.init(keyStore, "PKCS12Password".toCharArray());
            SSLContext sslContext = SSLContext.getDefault();
            socket = sslContext.getSocketFactory().createSocket(ipAddress, port);
            break;
        } catch (Exception e) {}
    }

I now still get javax.net.ssl.SSLHandshakeException: no cipher suites in common on the server (and javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure on the client).

What could be wrong?

3
  • Which Java version do you use on client and server? Commented Sep 3, 2015 at 15:20
  • Java 8u20 (of course including SDK) both on client and server (it is the same machine, and for ip I am currently using localhost). Commented Sep 4, 2015 at 9:51
  • Your server and client codes are both pointless. You initialise a KeyStore but you never use it. Have a good look at the JSSE Reference Guide. Commented Sep 5, 2015 at 9:41

1 Answer 1

1

I found the missing part of the puzzle (I believe).

Instead of the line SSLContext sslContext = SSLContext.getDefault(); on the client, I put:

    BufferedInputStream serverCertificateFile = new BufferedInputStream(new FileInputStream("somepath/server-cert.der"));
    X509Certificate serverCertificate = (X509Certificate)
              CertificateFactory.getInstance("X.509").generateCertificate(serverCertificateFile);
            sslContext.init(keyManagerFactory.getKeyManagers(), new TrustManager[] {
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] arg0,
                            String arg1) throws CertificateException {
                        throw new CertificateException();
                    }
                    @Override
                    public void checkServerTrusted(X509Certificate[] arg0,
                            String arg1) throws CertificateException {
                        boolean valid = false;
                        for (X509Certificate certificate : arg0) {
                            try {
                                certificate.verify(serverCertificate.getPublicKey());
                                valid = true;
                                break;
                            } catch (SignatureException e) {}
                        }
                        if (!valid) {
                            throw new CertificateException();
                        }
                    }
                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                }
            }, new SecureRandom());

server-cert.der is a file, created with openssl509 -outform der -in server-cert.pem -out server-cert.der.

I was not able to find good tutorials or question on this matter on StackOverflow, so this is what I created by attempting to understand the reference guide.

Essentially, I am creating a TrustManager that, for a server, trusts it when one of the provided certificates is the one that belongs to your own server.

It appears to work, please let me know if there is anything principally wrong with this approach (I unfortunately assume there is). Thanks for having read so much!

Sign up to request clarification or add additional context in comments.

2 Comments

i don't understand why you looked on StackOverflow first rather than the official documentation. Once you looked in the right place you found the answer immediately. There's a lesson there.
I did look at the official documentation first, and I still had to try various things before things worked, so I'm not sure I understand it even now. Like I said earlier, I couldn't connect the pieces of the puzzle...the official documentation was a maze to say the least. I wish there had been a tutorial.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.