2

I want to build TLS Multithreaded Client/Server Chat application, I am able to build simple Client Server using ServerSocket but I am having trouble with TLS:

  1. First there is no step by step guide to TLS Client/Server
  2. Communication All I could find was couple of question answer on stack-overflow I tried using that ones but failed SSL Socket connection

The errors I got were from server side:

Listening on [SSL: ServerSocket[addr=0.0.0.0/0.0.0.0,localport=786]] Connection from 21a947fe[SSL_NULL_WITH_NULL_NULL: Socket[addr=/127.0.0.1,port=39264,localport=786]] 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:1917) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:301) at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:291) at sun.security.ssl.ServerHandshaker.chooseCipherSuite(ServerHandshaker.java:1007) at sun.security.ssl.ServerHandshaker.clientHello(ServerHandshaker.java:724) at sun.security.ssl.ServerHandshaker.processMessage(ServerHandshaker.java:213) at sun.security.ssl.Handshaker.processLoop(Handshaker.java:925) at sun.security.ssl.Handshaker.process_record(Handshaker.java:860) at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1043) at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343) at sun.security.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:909)

And on Client Side:

javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure

Here is my server code :

public class Server {

// The ServerSocket we'll use for accepting new connections 
private SSLServerSocket server;
private final SSLContext sc;
private final Hashtable outputStreams;

// Constructor and while-accept loop all in one. 
public Server(int port) throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException {
    this.outputStreams = new Hashtable();
    KeyStore ks = initKeyStore(KEYSTORE, "JKS", KEYSTORE_PASSWORD);
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(
            KeyManagerFactory.getDefaultAlgorithm());

    kmf.init(ks, KEYSTORE_PASSWORD.toCharArray());

    TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
    tmf.init(ks);

    this.sc = SSLContext.getInstance("TLS");
    TrustManager[] trustManagers = tmf.getTrustManagers();
    this.sc.init(kmf.getKeyManagers(), trustManagers, null);
    // All we have to do is listen 
    listen(port);
}
private static final String KEYSTORE = "serverkeystore";
private static final String KEYSTORE_PASSWORD = "blackzero@server";

private static KeyStore initKeyStore(String keyStore, String keyStoreType, String keyPass) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
    KeyStore ks = null;
    try {

        ks = KeyStore.getInstance(keyStoreType);
        //ks.load(new FileInputStream(keyStore), keyPass.toCharArray());
        ks.load(null, keyPass.toCharArray());
    } catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException e) {
        Logger.getLogger(CNS.class.getName()).
                log(Level.SEVERE, null, e);
        //X509Certificate certificate = generateX509Certificate("CNS"); 
        ks = KeyStore.getInstance(keyStoreType);
        ks.load(null, keyPass.toCharArray());
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(2048);
        KeyPair kp = kpg.genKeyPair();
        Key publicKey = kp.getPublic();
        Key privateKey = kp.getPrivate();
        Certificate[] certChain = new Certificate[1];  
        certChain[0] = certificate;
        ks.setKeyEntry("key1", privateKey, KEYSTORE_PASSWORD.toCharArray(), certChain);
        try (FileOutputStream writeStream = new FileOutputStream(keyStore)) {
            ks.store(writeStream, keyPass.toCharArray());
        }
    }
    return ks;
}

private static X509Certificate generateX509Certificate(String certificateName) throws CertificateException, FileNotFoundException, IOException {
    InputStream inStream = null;
    X509Certificate cert = null;
    try {
        inStream = new FileInputStream(certificateName);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        cert = (X509Certificate) cf.generateCertificate(inStream);
    } finally {
        if (inStream != null) {
            inStream.close();
        }
    }
    return cert;
}

private void listen(int port) throws IOException {
    // Create the ServerSocket 
    SSLServerSocketFactory ssf = sc.getServerSocketFactory();
    server = (SSLServerSocket) ssf.createServerSocket(port);

    //server = new ServerSocket(port);
    // Tell the world we're ready to go 
    System.out.println("Listening on " + server);
    // Keep accepting connections forever 
    while (true) {
        // Grab the next incoming connection 
        SSLSocket s = (SSLSocket) server.accept();
        //Socket s = server.accept();
        // Tell the world we've got it 
        System.out.println("Connection from " + s);
        // Create a DataOutputStream for writing data to the 
        // other side 
        DataOutputStream dout = new DataOutputStream(s.getOutputStream());
        // Save this stream so we don't need to make it again 
        outputStreams.put(s, dout);
        // Create a new thread for this connection, and then forget // about it 
        new ServerThread(this, s);
    }
}

// Get an enumeration of all the OutputStreams, one for each client 
// connected to us 
Enumeration getOutputStreams() {
    return outputStreams.elements();
}

// Send a message to all clients (utility routine) 
void sendToAll(String message) {
    // We synchronize on this because another thread might be 
    // calling removeConnection() and this would screw us up 
    // as we tried to walk through the list 
    synchronized (outputStreams) {
        // For each client ... 
        for (Enumeration e = getOutputStreams(); e.hasMoreElements();) {
            // ... get the output stream ... 
            DataOutputStream dout = (DataOutputStream) e.nextElement();
            // ... and send the message 
            try {
                dout.writeUTF(message);
            } catch (IOException ie) {
                System.out.println(ie);
            }
        }
    }
}

// Remove a socket, and it's corresponding output stream, from our 
// list. This is usually called by a connection thread that has 
// discovered that the connectin to the client is dead. 
void removeConnection(Socket s) {
    // Synchronize so we don't mess up sendToAll() while it walks 
    // down the list of all output streamsa 
    synchronized (outputStreams) {
        // Tell the world 
        System.out.println("Removing connection to " + s);
        // Remove it from our hashtable/list 
        outputStreams.remove(s);
        // Make sure it's closed 
        try {
            s.close();
        } catch (IOException ie) {
            System.out.println("Error closing " + s);
            ie.printStackTrace();
        }
    }
}}

And client code:

public class Client implements Runnable {

private SSLSocket socket;
// The streams we communicate to the server; these come 
// from the socket private 
DataOutputStream dout;
private DataInputStream din;

// Constructor 
public Client(String host, int port) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException, KeyManagementException, java.security.cert.CertificateException {
    // Connect to the server 
    try {
        // Initiate the connection 
        KeyStore ks = initKeyStore(KEYSTORE, "JKS", KEYSTORE_PASSWORD);

        KeyManagerFactory kmf = KeyManagerFactory.getInstance(
            KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(ks, KEYSTORE_PASSWORD.toCharArray());

        TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
        tmf.init(ks);

        SSLContext sc = SSLContext.getInstance("TLS");
        TrustManager[] trustManagers = tmf.getTrustManagers();
        sc.init(kmf.getKeyManagers(), trustManagers, null);

        SSLSocketFactory ssf = sc.getSocketFactory();
        socket = (SSLSocket) ssf.createSocket(host, port);
        socket.startHandshake();
        //socket = new Socket(host, port);
        // We got a connection! Tell the world 
        System.out.println("connected to " + socket);
        // Let's grab the streams and create DataInput/Output streams 
        // from them 
        din = new DataInputStream(socket.getInputStream());
        dout = new DataOutputStream(socket.getOutputStream());
        // Start a background thread for receiving messages 
        new Thread(this).start();
    } catch (IOException ie) {
        System.out.println(ie);
    }
}

private static final String KEYSTORE = "clientkey.store";
private static final String KEYSTORE_PASSWORD = "blackzero@client";

private static KeyStore initKeyStore(String keyStore, String keyStoreType, String keyPass) throws KeyStoreException, IOException, NoSuchAlgorithmException, java.security.cert.CertificateException {
    KeyStore ks = null;
    try {
        ks = KeyStore.getInstance(keyStoreType);
        ks.load(null, keyPass.toCharArray());
    } catch (KeyStoreException | IOException | NoSuchAlgorithmException | java.security.cert.CertificateException e) {
        Logger.getLogger(Client.class.getName()).
                log(Level.SEVERE, null, e);
        ks.load(null, keyPass.toCharArray());
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
        kpg.initialize(2048);
        KeyPair kp = kpg.genKeyPair();
        Key publicKey = kp.getPublic();
        Key privateKey = kp.getPrivate();
        ks.setKeyEntry("keyForSeckeyDecrypt", privateKey, null, null);
        ks.setKeyEntry("keyForDigitalSignature", publicKey, null, null);
        try (FileOutputStream writeStream = new FileOutputStream(keyStore)) {
            ks.store(writeStream, keyPass.toCharArray());
        }
    }
    return ks;
}

// Gets called when the user types something 
private void processMessage(String message) {
    try {
        // Send it to the server 
        dout.writeUTF(message);
        // Clear out text input field 
        //tf.setText("");
    } catch (IOException ie) {
        System.out.println(ie);
    }
}

// Variables declaration - do not modify                     
// End of variables declaration                   
@Override
public void run() {
    try {
        // Receive messages one-by-one, forever 
        while (true) {
            // Get the next message 
            String message = din.readUTF();
            // Print it to our text window 
            //ta.append(message + "\n");
        }
    } catch (IOException ie) {
        System.out.println(ie);
    }
}

/**
 * @param args the command line arguments
 */
public static void main(String[] args) {
    // Get the port # from the command line 
    int port = 786;
    try {
        Client c1 = new Client("localhost", port);
        c1.processMessage("Hi c1 is here");
    } catch (KeyStoreException 
            | NoSuchAlgorithmException 
            | CertificateException 
            | UnrecoverableKeyException 
            | KeyManagementException 
            | java.security.cert.CertificateException ex) {
        Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
    }
}}

I will greatly appreciate it if you can point me to right direction.

Thanks, Attiqe

Community
  • 1
  • 1
Attiqe
  • 646
  • 1
  • 10
  • 22
  • 1. There is a JSSE Reference Guide provided with the Javadoc. 2. Initializing a keypair and certificate at runtime is futile, as the servr won't trust it. – user207421 Nov 15 '14 at 21:51

0 Answers0