Tech Brainwave

A Road Map for Innovative Technologies

Apache Mina – SSL Configuration

Posted by giftsam Posted on Dec - 12 - 2010

Introduction
Quite some time back, I had wrote an article to create a simple client/server application using Apache Mina 2.0.x. In that article the transaction between the client and server is unsecured.  In order to make a secured transaction between the client and the server, SSL should be configured. In this article, Let us see how to configure Secured Socket Layer(SSL) for a sample Client/Server application using 3 easy steps,

  1. Generate SSLContext
  2. Server part
  3. Client part

Step 1 – Generate SSLContext
SSLContext is a factory for secure socket or SSLEngine. For the sample application, A class named “SSLGenerator” is used to generate the SSLContext. To make a secured transaction, Two types of key files are needed they are “Keystore” and “Truststore” file. The Creation of these two files has been explained in the article “Step by step tutorial to create Keystore and Truststore file “. The factory classes used in the SSLContextGenerator class is,

KeyStoreFactory - This factory class is used to create and configures a new Keystore instance.

SSLContextFactory - This factory class is used to create and configures a new SSLContext.

SSLContextGenerator.java



package com.sample.ssl;

import java.io.File;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import org.apache.mina.filter.ssl.KeyStoreFactory;
import org.apache.mina.filter.ssl.SslContextFactory;

/**
* @author giftsam
*/
public class SSLContextGenerator
{
public SSLContext getSslContext()
{
SSLContext sslContext = null;
try
{
File keyStoreFile = new File("/home/giftsam/Desktop/certificates/keystore");
File trustStoreFile = new File("/home/giftsam/Desktop/certificates/truststore");

if (keyStoreFile.exists() && trustStoreFile.exists())
{
final KeyStoreFactory keyStoreFactory = new KeyStoreFactory();
System.out.println("Url is: " + keyStoreFile.getAbsolutePath());
keyStoreFactory.setDataFile(keyStoreFile);
keyStoreFactory.setPassword("techbrainwave");

final KeyStoreFactory trustStoreFactory = new KeyStoreFactory();
trustStoreFactory.setDataFile(trustStoreFile);
trustStoreFactory.setPassword("techbrainwave");

final SslContextFactory sslContextFactory = new SslContextFactory();
final KeyStore keyStore = keyStoreFactory.newInstance();
sslContextFactory.setKeyManagerFactoryKeyStore(keyStore);

final KeyStore trustStore = trustStoreFactory.newInstance();
sslContextFactory.setTrustManagerFactoryKeyStore(trustStore);
sslContextFactory.setKeyManagerFactoryKeyStorePassword("techbrainwave");
sslContext = sslContextFactory.newInstance();
System.out.println("SSL provider is: " + sslContext.getProvider());
}
else
{
System.out.println("Keystore or Truststore file does not exist");
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
return sslContext;
}
}


Step 2 – Server part
For the server part two classes named “SSLServer” and “SSLServerHandler” has been used.  In the SSLServer class,  “SSLFilter” class is used to encrypt and decrypt the data exchanged in the session, Also it triggers the SSLHandshake procedure immediately(If you don’t want the handshake procedure to start immediately, please specify false as autostart parameter in the constructor).

Note: SSLFilter works only for the TCP/IP connections.

An interface named “IoAcceptor” is used to accept the incoming connections from the client and that fires the event to the handler. Two filters has been used, the first one is the “LoggingFilter” which logs all the events and requests and the second one is the “ProtocolCodecFilter” which is used to convert an incoming ByteBuffer into message POJO.

SSLServer.java



package com.sample.ssl;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import org.apache.mina.core.filterchain.DefaultIoFilterChainBuilder;

import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.service.IoAcceptor;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.filter.ssl.SslFilter;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;

/**
* @author giftsam
*/
public class SSLServer
{
private static final int PORT = 5000;

private static void addSSLSupport(DefaultIoFilterChainBuilder chain)
{
try
{
SslFilter sslFilter = new SslFilter(new SSLContextGenerator().getSslContext());
chain.addLast("sslFilter", sslFilter);
System.out.println("SSL support is added..");
}
catch (Exception ex)
{
ex.printStackTrace();
}
}

public static void main(String[] args) throws IOException, GeneralSecurityException
{
IoAcceptor acceptor = new NioSocketAcceptor();
DefaultIoFilterChainBuilder chain = acceptor.getFilterChain();

addSSLSupport(chain);

chain.addLast("logger", new LoggingFilter());
chain.addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));

acceptor.setHandler(new SSLServerHandler());
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
acceptor.bind(new InetSocketAddress(PORT));
System.out.println("Server Started..");
}
}


The SSLServerHandler class contains four methods. The first method “sessionOpened” is called when the session is opened and it is used to set the session idle time. The second method “receiveMessage” is used to receive the message sent by the client. The other two methods “sessionIdle” is used to close the session when it was idle for 10 secs and the fourth method “exceptionCaught” is used to close the session when an exception occured.

SSLServerHandler.java


package com.sample.ssl;

import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author giftsam
*/
public class SSLServerHandler extends IoHandlerAdapter
{
private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());
private int idleTimeout = 10;

@Override
public void sessionOpened(IoSession session)
{
// set idle time to 10 seconds
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, idleTimeout);

session.setAttribute("Values: ");
}

@Override
public void messageReceived(IoSession session, Object message)
{
System.out.println("Message received in the server..");
System.out.println("Message is: " + message.toString());
}

@Override
public void sessionIdle(IoSession session, IdleStatus status)
{
logger.info("Transaction is idle for " + idleTimeout + "secs, So disconnecting..");
// disconnect an idle client
session.close();
}

@Override
public void exceptionCaught(IoSession session, Throwable cause)
{
// close the connection on exceptional situation
session.close();
}
}

Step 3 – Client part
For the client part two classes named “SSLClient” and “SSLClientHandler” has been used. In the “MinaClient” class the SSLFilter class is used to encrypt and decrypt the data exchanged in the session and SSLFilter property  UseClientMode should be set as true and that configures the socket to use client mode in its first handshake.

“IoConnector” interface is used to communicate with the server and that fires the event to the handler. Like the server part, The same “LoggingFilter” and “ProtocolCodecFilter” has been used. An interface named “ConnectFuture” is used to windup the asynchronous connection requests.

SSLClient.java

package com.sample.ssl;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.security.GeneralSecurityException;
import javax.net.ssl.SSLContext;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.service.IoConnector;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filter.codec.textline.TextLineCodecFactory;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.filter.ssl.SslFilter;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

/**
* @author giftsam
*/
public class SSLClient
{
private static final int REMORT_PORT = 5000;

public static void main(String[] args) throws IOException, InterruptedException, GeneralSecurityException
{
IoConnector connector = new NioSocketConnector();
connector.getSessionConfig().setReadBufferSize(2048);

SSLContext sslContext = new SSLContextGenerator().getSslContext();
System.out.println("SSLContext protocol is: " + sslContext.getProtocol());

SslFilter sslFilter = new SslFilter(sslContext);
sslFilter.setUseClientMode(true);
connector.getFilterChain().addFirst("sslFilter", sslFilter);

connector.getFilterChain().addLast("logger", new LoggingFilter());
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));

connector.setHandler(new SSLClientHandler("Hello Server.."));
ConnectFuture future = connector.connect(new InetSocketAddress("172.108.0.6", REMORT_PORT));
future.awaitUninterruptibly();

if (!future.isConnected())
{
return;
}
IoSession session = future.getSession();
session.getConfig().setUseReadOperation(true);
session.getCloseFuture().awaitUninterruptibly();
System.out.println("After Writing");
connector.dispose();
}
}

For the handler, Like the server part the same methods “sessionOpened”, “messageReceived” and “exceptionCaught” has been used.

SSLClientHandler.java


package com.sample.ssl;

import org.apache.mina.core.service.IoHandlerAdapter;
import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* @author giftsam
*/
public class SSLClientHandler extends IoHandlerAdapter
{
private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());
private final String values;
private boolean finished;

public SSLClientHandler(String values)
{
this.values = values;
}

public boolean isFinished()
{
return finished;
}

@Override
public void sessionOpened(IoSession session)
{
session.write(values);
}

@Override
public void messageReceived(IoSession session, Object message)
{
logger.info("Message received in the client..");
logger.info("Message is: " + message.toString());
}

@Override
public void exceptionCaught(IoSession session, Throwable cause)
{
session.close();
}
}

Now its time to test the preceding codes, First the code “SSLServer” should be executed and then execute the “SSLClient”, the outcome of the codes will looks like the below,

Output – Server


Url is: /home/giftsam/Desktop/certificates/keystore
SSL Provider is: SunJSSE version 1.6
SSL support is added..
Server Started..
Dec 10, 2010 8:37:59 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: CREATED
Dec 10, 2010 8:37:59 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: OPENED
Dec 10, 2010 8:37:59 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: RECEIVED: HeapBuffer[pos=0 lim=15 cap=36: 48 65 6C 6C 6F 20 53 65 72 76 65 72 2E 2E 0A]
Message received in the server..
Message is: Hello Server..
Dec 10, 2010 8:38:09 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: IDLE
Dec 10, 2010 8:38:09 PM com.sample.ssl.SSLServerHandler sessionIdle
INFO: Transaction is idle for 10secs, So disconnecting..
Dec 10, 2010 8:38:09 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: CLOSED

Output – client


Url is: /home/giftsam/Desktop/certificates/keystore
SSL Provider is: SunJSSE version 1.6
SSLContext protocol is: TLS
Dec 10, 2010 8:37:59 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: CREATED
Dec 10, 2010 8:37:59 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: OPENED
Dec 10, 2010 8:37:59 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: SENT: HeapBuffer[pos=0 lim=15 cap=16: 48 65 6C 6C 6F 20 53 65 72 76 65 72 2E 2E 0A]
Dec 10, 2010 8:37:59 PM org.apache.mina.filter.logging.LoggingFilter log
INFO: SENT: HeapBuffer[pos=0 lim=0 cap=0: empty]

Thats all folks. I hope this article clearly explains the steps to implement SSL for a client/server application using Apache Mina 2.0.x. If you find this article is useful for you, dont forget to leave your valuable comments. Have a joyous code day.

11 Responses so far.

  1. Excellent article. I was able to reuse your Mina server side code and I successfully was able to do an SSL handshaking against a Flex application using the AS3 Crypto library.

    Thanks for sharing.

    Alberto

    Thumb up 1 Thumb down 0

    [Reply]

  2. SS says:

    Nice article..
    cheers

    Thumb up 2 Thumb down 0

    [Reply]

  3. Parijat Bansal says:

    Thanks for such an easy to understand post. Saved me a lot of time.

    Thumb up 3 Thumb down 0

    [Reply]

  4. Irfan Pervez says:

    hello all,
    please help me getting following exception while execution of code.

    Url is: C:\Java\jdk1.6.0\bin\keystore.JKS
    java.io.IOException: Keystore was tampered with, or password was incorrect
    at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:771)
    at sun.security.provider.JavaKeyStore$JKS.engineLoad(JavaKeyStore.java:38)
    at java.security.KeyStore.load(KeyStore.java:1185)
    at org.apache.mina.filter.ssl.KeyStoreFactory.newInstance(KeyStoreFactory.java:68)
    at com.sample.ssl.SSLContextGenerator.getSslContext(SSLContextGenerator.java:64)
    at com.sample.ssl.SSLClient.main(SSLClient.java:55)
    Caused by: java.security.UnrecoverableKeyException: Password verification failed
    at sun.security.provider.JavaKeyStore.engineLoad(JavaKeyStore.java:769)
    … 5 more
    Exception in thread “main” java.lang.NullPointerException
    at com.sample.ssl.SSLClient.main(SSLClient.java:57)

    Thumb up 0 Thumb down 0

    [Reply]

  5. shashi says:

    very good article and clear with step by step approch

    Thumb up 3 Thumb down 0

    [Reply]

  6. deepika says:

    I am getting “Keystore or Truststore file does not exist” , i have given the file path where the keystore.jks and truststore.jks are generated i.e;C:/Program Files/Java/jdk1.5.0_15/binkeystore.jks.Pls let me know where is the problem.

    Thumb up 1 Thumb down 0

    [Reply]

  7. Rajesh says:

    Hi,

    I am getting following exception

    SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder”.
    SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
    Exception in thread “main” java.lang.NoClassDefFoundError: org/slf4j/impl/StaticLoggerBinder
    at org.slf4j.LoggerFactory.(LoggerFactory.java:60)
    at org.apache.mina.core.service.AbstractIoService.(AbstractIoService.java:64)
    at SSLClient.main(SSLClient.java:22)
    Caused by: java.lang.ClassNotFoundException: org.slf4j.impl.StaticLoggerBinder
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    … 3 more

    Thanks
    Rajesh

    Thumb up 0 Thumb down 0

    [Reply]

  8. vidya sagar says:

    i am trying to build a proxy server based on the example given in the apache mina distribution.i am able to achieve http and when i try to connect to a https enabled websites i am not able to.please guide me how to do this.

    Thumb up 0 Thumb down 0

    [Reply]

  9. Madhurima says:

    Hi ALL,

    Please help me.

    Is Mina SSL Server accept c++ SSL Client request.
    If possible someone can provide me the server.

    Thanks,
    Madhurima v

    Thumb up 0 Thumb down 0

    [Reply]

  10. Adalbert says:

    Hey, but is this realife example ?. In Your code client is reading keystore and truststore from the same files as server does. It works only on one machine or what ? Maybe Am I missing something.

    Thumb up 0 Thumb down 0

    [Reply]

  11. roop says:

    Hi,

    thanks for this nice tutorial. One thing i’m a bit confused about is the fact that SSLContextGenerator needs keystore-file AND truststore-file. If i got it right then keystore-file contains private/public key. The idea behind this is not to give private-key away, right? So SSLContextGenerator should look different right?

    greetings roop

    Thumb up 2 Thumb down 0

    [Reply]