1

we are currently working on a server program written in Java that uses TLS. To achieve this, we used the Java SSLServerSocket. However, everytime a client tried to connect to the server, it caused a javax.net.ssl.SSLHandshakeException when the server attempted to start the handshake. To resolve this, we extracted the relevant code part and wrote a debugging server and client program, but still the same errors occurred.

We have the latest version of Java installed (8u111) and it's a regular Oracle version. The cipher suite we chose should definitely be supported since it was on the list from SSLSocket.getSupportedCipherSuites().

We read other threads on this forum suggesting various things like disabling ciphers using Diffie-Hellman or using a cipher with RSA signing instead of ECDSA, but nothing fixed it.

The server program

package ch.debugging.server

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.util.encoders.Base64;

import javax.net.ssl.*;
import java.io.*;
import java.math.BigInteger;
import java.net.BindException;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Date;


public class Main {

    public static void main(String[] args) {

        KeyStore keystore = null;
        try {
            BouncyCastleProvider bc = new BouncyCastleProvider();
            File keystoreFile = new File("D:\\keystore.asdf");
            keystore = KeyStore.getInstance("JKS");

        //Create new keystore if there is none
            if (!keystoreFile.exists()) {
                SecureRandom r = SecureRandom.getInstanceStrong();

                KeyPairGenerator keygen = KeyPairGenerator.getInstance("EC", bc);
                keygen.initialize(384, r);
                KeyPair keys = keygen.generateKeyPair();
                System.out.println("Keys successfully generated");

                //Parameters for the certificate
                X500Name issuer = new X500Name("C=, ST=, L=, O=, OU=, CN=");
                X500Name subject = issuer; //self-signed certificate: issuer and subject are the same
                BigInteger serial = BigInteger.valueOf(r.nextLong());
                Date notBefore = new Date(System.currentTimeMillis());
                Date notAfter = new Date(System.currentTimeMillis() + (1000 * 3600 * 24 * 365 * 10)); //valid for one year from now

                //Build the certificate
                X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, keys.getPublic());
                ContentSigner signer = new JcaContentSignerBuilder("SHA512WithECDSA").build(keys.getPrivate());
                X509CertificateHolder certHolder = certGen.build(signer);
                X509Certificate[] certChain = {new JcaX509CertificateConverter().setProvider(bc).getCertificate(certHolder)};
                System.out.println(Base64.toBase64String(certChain[0].getEncoded()));
                System.out.println("Certificate built");

                //Save keys and the certificate to keystore
                keystore.load(null, "123456".toCharArray());
                keystore.setCertificateEntry("Certificate", certChain[0]);
                keystore.store(new FileOutputStream(keystoreFile), "123456".toCharArray());
                System.out.println("Certificate saved in keystore");
            }
        //load keystore if it exists
            else {
                keystore.load(new FileInputStream(keystoreFile), "123456".toCharArray());
                System.out.println("Keystore loaded");
            }
        } catch(Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
        try {
            SecureRandom r = SecureRandom.getInstanceStrong();
            //Prepare SSLServerSocket
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            kmf.init(keystore,"123456".toCharArray());
            tmf.init(keystore);
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(kmf.getKeyManagers(),tmf.getTrustManagers(),r);

            //Create and set up server socket
            SSLServerSocketFactory factory = sslContext.getServerSocketFactory();
            SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(6060);

            serverSocket.setEnabledProtocols(new String[]{"TLSv1.2"});
            serverSocket.setEnabledCipherSuites(new String[]{"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
            serverSocket.setEnableSessionCreation(true);
            serverSocket.setNeedClientAuth(false);
            System.out.println("Waiting for incoming connections...");
            SSLSocket s = (SSLSocket) serverSocket.accept();
            s.startHandshake();
            System.out.println("------Connection established------");
            BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
            while (true) {
                System.out.println(in.readLine());
            }
        } catch(BindException bind) {
            System.out.println("Failed to bind port 6060. Is it already in use?");
            bind.printStackTrace();
        } catch(IOException io) {
            io.printStackTrace();
        } catch(Exception kse) {
            kse.printStackTrace();
        }
    }
}

The client program

import javax.net.ssl.*;
import javax.swing.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.security.KeyStore;
import java.security.SecureRandom;


public class main {
    public static void main(String[] args) {
        try {

            //Load keystore
            KeyStore keystore = KeyStore.getInstance("JKS");
            keystore.load(new FileInputStream(new File("D:\\keystore.asdf")), "123456".toCharArray());

            //Prepare SSLServerSocket
            SecureRandom r = SecureRandom.getInstanceStrong();
            KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            kmf.init(keystore,"123456".toCharArray());
            tmf.init(keystore);

            //initialize SSLContext
            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
            sslContext.init(kmf.getKeyManagers(),tmf.getTrustManagers(),r);
            SSLSocketFactory factory = sslContext.getSocketFactory();
            SSLSocket socket = (SSLSocket) factory.createSocket();

            socket.setEnabledProtocols(new String[]{"TLSv1.2"});
            socket.setEnabledCipherSuites(new String[]{"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"});
            socket.setEnableSessionCreation(true);
            socket.connect(new InetSocketAddress("localhost",6060));
            socket.startHandshake();
            PrintWriter out = new PrintWriter(socket.getOutputStream(),true);

            while (true) {
                String msg = JOptionPane.showInputDialog(null,"Message");
                if (!msg.equalsIgnoreCase("")) {
                    out.println(msg);
                } else {
                    socket.close();
                    break;
                }
            }
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

The output of the server program (with -Djavax.net.debug=ssl,handshake)

Keystore loaded

adding as trusted cert:

Subject: CN=, OU=, O=, L=, ST=, C=

Issuer: CN=, OU=, O=, L=, ST=, C=

Algorithm: EC; Serial number: 0x-dde391bb99f8ce8

Valid from Fri Dec 30 13:55:36 CET 2016 until Fri Jan 20 17:32:03 CET 2017

trigger seeding of SecureRandom

done seeding SecureRandom

Waiting for incoming connections...

Allow unsafe renegotiation: false

Allow legacy hello messages: true

Is initial handshake: true

Is secure renegotiation: false

main, READ: TLSv1.2 Handshake, length = 140

*** ClientHello, TLSv1.2

RandomCookie: GMT: 1483105145 bytes = { 70, 211, 55, 52, 24, 196, 174, 198, 164, 57, 157, 130, 143, 21, 91, 86, 53, 112, 138, 55, 208, 249, 218, 82, 245, 224, 32, 184 }

Session ID: {}

Cipher Suites: [TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384]

Compression Methods: { 0 }

Extension elliptic_curves, curve names: {secp256r1, sect163k1, sect163r2, secp192r1, secp224r1, sect233k1, sect233r1, sect283k1, sect283r1, secp384r1, sect409k1, sect409r1, secp521r1, sect571k1, sect571r1, secp160k1, secp160r1, secp160r2, sect163r1, secp192k1, sect193r1, sect193r2, secp224k1, sect239k1, secp256k1}

Extension ec_point_formats, formats: [uncompressed]

Extension signature_algorithms, signature_algorithms: SHA512withECDSA, SHA512withRSA, SHA384withECDSA, SHA384withRSA, SHA256withECDSA, SHA256withRSA, SHA256withDSA, SHA1withECDSA, SHA1withRSA, SHA1withDSA

Extension renegotiation_info, renegotiated_connection:


%% Initialized: [Session-1, SSL_NULL_WITH_NULL_NULL]

%% Invalidated: [Session-1, SSL_NULL_WITH_NULL_NULL]

main, SEND TLSv1.2 ALERT: fatal, description = handshake_failure

main, WRITE: TLSv1.2 Alert, length = 2

main, called closeSocket()

main, handling exception: javax.net.ssl.SSLHandshakeException: no cipher suites in common

javax.net.ssl.SSLHandshakeException: no cipher suites in common
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:292)
    at sun.security.ssl.ServerHandshaker.chooseCipherSuite(ServerHandshaker.java:1035)
    at sun.security.ssl.ServerHandshaker.clientHello(ServerHandshaker.java:738)
    at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:221)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at ch.debugging.server.Main.main(Main.java:93)

The output of the client program

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:154)
    at sun.security.ssl.SSLSocketImpl.recvAlert(SSLSocketImpl.java:2023)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1125)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
    at main.main(main.java:38)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

Thanks for your help.

tmf1234
  • 11
  • 3
  • Connecting to your server with the openssl client presents no server certificate, this is probably the issue. – Raniz Dec 30 '16 at 14:39
  • Thank you very very much. I was able to solve the problem by replacing keystore.setCertificateEntry("Certificate",certChain[0]); by keystore.setKeyEntry("Certificate",keys.getPrivate(),"123456".toCharArray(),certChain); thanks to your post. This way, the private key is saved in the keystore which I presume is needed for the server. – tmf1234 Dec 30 '16 at 14:54

0 Answers0