title: Netty SSL: Chat Client example with custom keystore is unable to accept multiple connections
body: <p>I've been playing with Netty's (version 4.0.24) SecureChatServer examples and i've plugged in my own keystore (based on the answers found on the following two posts <a href="https://stackoverflow.com/questions/10509358/using-ssl-certificates-on-netty">post 1</a> and <a href="https://stackoverflow.com/questions/9573894/set-up-netty-with-2-way-ssl-handsake-client-and-server-certificate">post2</a>.  See code snippets below.</p>
  
  <p>The issue i'm seeing is that everything works as expected when I run one instance of the client, but when i try to launch more client instances i get exceptions on both the server and client (see below for exception text) and at that point the server stops responding.</p>
  
  <p>I'm hoping someone here could shed some light into what i'm doing wrong.</p>
  
  <p>This is the class that handles loading my keyStore and creating SSLContext instances used by both client/server (for obvious reasons i've omitted my keystore values):</p>
  
  <pre><code>package com.test.securechat;
  
  import java.io.ByteArrayInputStream;
  import java.security.KeyStore;
  import javax.net.ssl.KeyManagerFactory;
  import javax.net.ssl.SSLContext;
  import javax.net.ssl.TrustManagerFactory;
  
  import com.test.util.Key;
  import com.pragmafs.util.encryption.Base64Coder;
  
  /**
   * Creates SSLContext instances from a static (String representation) keystore
   * See http://maxrohde.com/2013/09/07/setting-up-ssl-with-netty/
   */
  public class SslContextFactory {
      private static final String PROTOCOL = "TLS";
      private static final SSLContext SERVER_CONTEXT;
      private static final SSLContext CLIENT_CONTEXT;
      private static final TrustManagerFactory trustManagerFactory;
  
      static {
  
          SSLContext serverContext = null;
          SSLContext clientContext = null;
  
          try {
  
              KeyStore ks = KeyStore.getInstance("JKS");
              ks.load(new ByteArrayInputStream(Base64Coder.decode(Key.SSL.getKey())), Base64Coder.decodeString(Key.SSL.getPwd()).toCharArray());
  
              // Set up key manager factory to use our key store
              KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
              kmf.init(ks, Base64Coder.decodeString(Key.SSL.getPwd()).toCharArray());
  
              // truststore
              KeyStore ts = KeyStore.getInstance("JKS");
              ts.load(new ByteArrayInputStream(Base64Coder.decode(Key.SSL.getKey())), Base64Coder.decodeString(Key.SSL.getPwd()).toCharArray());
  
              // set up trust manager factory to use our trust store
              trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
              trustManagerFactory.init(ts);
  
              // Initialize the SSLContext to work with our key managers.
              serverContext = SSLContext.getInstance(PROTOCOL);
              serverContext.init(kmf.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
  
              clientContext = SSLContext.getInstance(PROTOCOL);
              clientContext.init(null, trustManagerFactory.getTrustManagers(), null);
          } catch (Exception e) {
              throw new Error("Failed to initialize the SSLContext", e);
          }
  
          SERVER_CONTEXT = serverContext;
          CLIENT_CONTEXT = clientContext;
      }
  
  
      public static SSLContext getServerContext() {
          return SERVER_CONTEXT;
      }
  
      public static SSLContext getClientContext() {
          return CLIENT_CONTEXT;
      }
  
      public static TrustManagerFactory getTrustManagerFactory() {
          return trustManagerFactory;
      }
  
      private SslContextFactory() {
          // Unused
      }
  }
  </code></pre>
  
  <p>This is the server code:</p>
  
  <pre><code>package com.test.securechat;
  
  import java.net.InetAddress;
  import javax.net.ssl.SSLEngine;
  
  import io.netty.bootstrap.ServerBootstrap;
  import io.netty.channel.Channel;
  import io.netty.channel.ChannelHandlerContext;
  import io.netty.channel.ChannelInitializer;
  import io.netty.channel.ChannelPipeline;
  import io.netty.channel.EventLoopGroup;
  import io.netty.channel.SimpleChannelInboundHandler;
  import io.netty.channel.group.ChannelGroup;
  import io.netty.channel.group.DefaultChannelGroup;
  import io.netty.channel.nio.NioEventLoopGroup;
  import io.netty.channel.socket.SocketChannel;
  import io.netty.channel.socket.nio.NioServerSocketChannel;
  import io.netty.handler.codec.DelimiterBasedFrameDecoder;
  import io.netty.handler.codec.Delimiters;
  import io.netty.handler.codec.string.StringDecoder;
  import io.netty.handler.codec.string.StringEncoder;
  import io.netty.handler.logging.LogLevel;
  import io.netty.handler.logging.LoggingHandler;
  import io.netty.handler.ssl.SslHandler;
  import io.netty.util.concurrent.Future;
  import io.netty.util.concurrent.GenericFutureListener;
  import io.netty.util.concurrent.GlobalEventExecutor;
  
  
  /**
   * Simple SSL chat server
   */
  public final class SecureChatServer {
  
      static final int PORT = Integer.parseInt(System.getProperty("port", "8992"));
  
      public static void main(String[] args) throws Exception {
  
          SSLEngine sslEngine = SslContextFactory.getServerContext().createSSLEngine();
          sslEngine.setUseClientMode(false);
  
          EventLoopGroup bossGroup = new NioEventLoopGroup(1);
          EventLoopGroup workerGroup = new NioEventLoopGroup();
  
          try {
              ServerBootstrap b = new ServerBootstrap();
              b.group(bossGroup, workerGroup)
                      .channel(NioServerSocketChannel.class)
                      .handler(new LoggingHandler(LogLevel.INFO))
                      .childHandler(new SecureChatServerInitializer(sslEngine));
  
              b.bind(PORT).sync().channel().closeFuture().sync();
          } finally {
              bossGroup.shutdownGracefully();
              workerGroup.shutdownGracefully();
          }
      }
  
      private static class SecureChatServerInitializer extends ChannelInitializer&lt;SocketChannel&gt; {
  
          private final SSLEngine sslCtx;
  
          public SecureChatServerInitializer(SSLEngine sslCtx) {
              this.sslCtx = sslCtx;
          }
  
          @Override
          public void initChannel(SocketChannel ch) throws Exception {
              ChannelPipeline pipeline = ch.pipeline();
  
              pipeline.addLast(new SslHandler(sslCtx));
              pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
              pipeline.addLast(new StringDecoder());
              pipeline.addLast(new StringEncoder());
  
              // and then business logic.
              pipeline.addLast(new SecureChatServerHandler());
          }
      }
  
      private static class SecureChatServerHandler extends SimpleChannelInboundHandler&lt;String&gt; {
  
          static final ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
  
          @Override
          public void channelActive(final ChannelHandlerContext ctx) {
              // Once session is secured, send a greeting and register the channel to the global channel
              // list so the channel received the messages from others.
              ctx.pipeline().get(SslHandler.class).handshakeFuture().addListener(
                      new GenericFutureListener&lt;Future&lt;Channel&gt;&gt;() {
                          @Override
                          public void operationComplete(Future&lt;Channel&gt; future) throws Exception {
                              ctx.writeAndFlush(
                                      "Welcome to " + InetAddress.getLocalHost().getHostName() + " secure chat service!\n");
                              ctx.writeAndFlush(
                                      "Your session is protected by " +
                                              ctx.pipeline().get(SslHandler.class).engine().getSession().getCipherSuite() +
                                              " cipher suite.\n");
  
                              channels.add(ctx.channel());
                          }
                      });
          }
  
          @Override
          public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
              // Send the received message to all channels but the current one.
              for (Channel c : channels) {
                  if (c != ctx.channel()) {
                      c.writeAndFlush("[" + ctx.channel().remoteAddress() + "] " + msg + '\n');
                  } else {
                      c.writeAndFlush("[you] " + msg + '\n');
                  }
              }
  
              // Close the connection if the client has sent 'bye'.
              if ("bye".equals(msg.toLowerCase())) {
                  ctx.close();
              }
          }
  
          @Override
          public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
              cause.printStackTrace();
              ctx.close();
          }
      }
  }
  </code></pre>
  
  <p>Client code:</p>
  
  <pre><code>package com.test.securechat;
  
  import java.io.BufferedReader;
  import java.io.InputStreamReader;
  import javax.net.ssl.SSLEngine;
  
  import io.netty.bootstrap.Bootstrap;
  import io.netty.channel.Channel;
  import io.netty.channel.ChannelFuture;
  import io.netty.channel.ChannelHandlerContext;
  import io.netty.channel.ChannelInitializer;
  import io.netty.channel.ChannelPipeline;
  import io.netty.channel.EventLoopGroup;
  import io.netty.channel.SimpleChannelInboundHandler;
  import io.netty.channel.nio.NioEventLoopGroup;
  import io.netty.channel.socket.SocketChannel;
  import io.netty.channel.socket.nio.NioSocketChannel;
  import io.netty.handler.codec.DelimiterBasedFrameDecoder;
  import io.netty.handler.codec.Delimiters;
  import io.netty.handler.codec.string.StringDecoder;
  import io.netty.handler.codec.string.StringEncoder;
  import io.netty.handler.ssl.SslHandler;
  
  /**
   * Simple SSL chat client
   */
  public final class SecureChatClient {
  
      static final String HOST = System.getProperty("host", "127.0.0.1");
      static final int PORT = Integer.parseInt(System.getProperty("port", "8992"));
  
      public static void main(String[] args) throws Exception {
  
          SSLEngine engine = SslContextFactory.getClientContext().createSSLEngine();
          engine.setUseClientMode(true);
  
          EventLoopGroup group = new NioEventLoopGroup();
          try {
              Bootstrap b = new Bootstrap();
              b.group(group)
                      .channel(NioSocketChannel.class)
                      .handler(new SecureChatClientInitializer(engine));
  
              // Start the connection attempt.
              Channel ch = b.connect(HOST, PORT).sync().channel();
  
              // Read commands from the stdin.
              ChannelFuture lastWriteFuture = null;
              BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
              for (; ; ) {
                  String line = in.readLine();
                  if (line == null) {
                      break;
                  }
  
                  // Sends the received line to the server.
                  lastWriteFuture = ch.writeAndFlush(line + "\r\n");
  
                  // If user typed the 'bye' command, wait until the server closes
                  // the connection.
                  if ("bye".equals(line.toLowerCase())) {
                      ch.closeFuture().sync();
                      break;
                  }
              }
  
              // Wait until all messages are flushed before closing the channel.
              if (lastWriteFuture != null) {
                  lastWriteFuture.sync();
              }
          } finally {
              // The connection is closed automatically on shutdown.
              group.shutdownGracefully();
          }
      }
  
      private static class SecureChatClientInitializer extends ChannelInitializer&lt;SocketChannel&gt; {
  
          private final SSLEngine sslCtx;
  
          public SecureChatClientInitializer(SSLEngine sslCtx) {
              this.sslCtx = sslCtx;
          }
  
          @Override
          public void initChannel(SocketChannel ch) throws Exception {
              ChannelPipeline pipeline = ch.pipeline();
  
              // Add SSL handler first to encrypt and decrypt everything.
              // In this example, we use a bogus certificate in the server side
              // and accept any invalid certificates in the client side.
              // You will need something more complicated to identify both
              // and server in the real world.
              //pipeline.addLast(sslCtx.newHandler(ch.alloc(), SecureChatClient.HOST, SecureChatClient.PORT));
              pipeline.addLast(new SslHandler(sslCtx));
  
              // On top of the SSL handler, add the text line codec.
              pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
              pipeline.addLast(new StringDecoder());
              pipeline.addLast(new StringEncoder());
              //pipeline.addLast(new LoggingHandler(LogLevel.INFO));
  
  
              // and then business logic.
              pipeline.addLast(new SecureChatClientHandler());
          }
      }
  
      private static class SecureChatClientHandler extends SimpleChannelInboundHandler&lt;String&gt; {
  
          @Override
          public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
              System.err.println(msg);
          }
  
          @Override
          public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
              cause.printStackTrace();
              ctx.close();
          }
      }
  }
  </code></pre>
  
  <p>Server Exception: </p>
  
  <pre><code>INFO: [id: 0x5eb2ac7a, /0:0:0:0:0:0:0:0:8992] RECEIVED: [id: 0x7d7a7dca, /127.0.0.1:55932 =&gt; /127.0.0.1:8992]
  io.netty.handler.codec.DecoderException: javax.net.ssl.SSLHandshakeException: ciphertext sanity check failed
      at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:278)
      at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:147)
      at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:333)
      at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:319)
      at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:787)
      at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:130)
      at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
      at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
      at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
      at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
      at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
      at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
      at java.lang.Thread.run(Thread.java:744)
  Caused by: javax.net.ssl.SSLHandshakeException: ciphertext sanity check failed
      at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
      at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1683)
      at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:959)
      at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:884)
      at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:758)
      at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
      at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:995)
      at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:921)
      at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:867)
      at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:247)
      ... 12 more
  Caused by: javax.crypto.BadPaddingException: ciphertext sanity check failed
      at sun.security.ssl.InputRecord.decrypt(InputRecord.java:147)
      at sun.security.ssl.EngineInputRecord.decrypt(EngineInputRecord.java:192)
      at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:953)
      ... 19 more
  </code></pre>
  
  <p>Client exception:</p>
  
  <pre><code>io.netty.handler.codec.DecoderException: javax.net.ssl.SSLException: Received fatal alert: &lt;UNKNOWN ALERT: 170&gt;
      at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:278)
      at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:147)
      at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:333)
      at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:319)
      at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:787)
      at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:130)
      at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
      at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
      at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
      at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
      at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
      at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
      at java.lang.Thread.run(Thread.java:744)
  Caused by: javax.net.ssl.SSLException: Received fatal alert: &lt;UNKNOWN ALERT: 170&gt;
      at sun.security.ssl.Alerts.getSSLException(Alerts.java:208)
      at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1619)
      at sun.security.ssl.SSLEngineImpl.fatal(SSLEngineImpl.java:1587)
      at sun.security.ssl.SSLEngineImpl.recvAlert(SSLEngineImpl.java:1756)
      at sun.security.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:1060)
      at sun.security.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:884)
      at sun.security.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:758)
      at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:624)
      at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:995)
      at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:921)
      at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:867)
      at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:247)
      ... 12 more
  </code></pre>