java - Netty SSL: Chat Client example with custom keystore is unable to accept multiple connections -



java - Netty SSL: Chat Client example with custom keystore is unable to accept multiple connections -

i've been playing netty's (version 4.0.24) securechatserver examples , i've plugged in own keystore (based on answers found on next 2 posts post 1 , post2. see code snippets below.

the issue i'm seeing works expected when run 1 instance of client, when seek launch more client instances exceptions on both server , client (see below exception text) , @ point server stops responding.

i'm hoping here shed lite i'm doing wrong.

this class handles loading keystore , creating sslcontext instances used both client/server (for obvious reasons i've omitted keystore values):

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 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; seek { keystore ks = keystore.getinstance("jks"); ks.load(new bytearrayinputstream(base64coder.decode(key.ssl.getkey())), base64coder.decodestring(key.ssl.getpwd()).tochararray()); // set key manager mill utilize 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 trust manager mill utilize our trust store trustmanagerfactory = trustmanagerfactory.getinstance(trustmanagerfactory.getdefaultalgorithm()); trustmanagerfactory.init(ts); // initialize sslcontext work our key managers. servercontext = sslcontext.getinstance(protocol); servercontext.init(kmf.getkeymanagers(), trustmanagerfactory.gettrustmanagers(), null); clientcontext = sslcontext.getinstance(protocol); clientcontext.init(null, trustmanagerfactory.gettrustmanagers(), null); } grab (exception e) { throw new error("failed initialize sslcontext", e); } server_context = servercontext; client_context = clientcontext; } public static sslcontext getservercontext() { homecoming server_context; } public static sslcontext getclientcontext() { homecoming client_context; } public static trustmanagerfactory gettrustmanagerfactory() { homecoming trustmanagerfactory; } private sslcontextfactory() { // unused } }

this server 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(); seek { 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(); } { bossgroup.shutdowngracefully(); workergroup.shutdowngracefully(); } } private static class securechatserverinitializer extends channelinitializer<socketchannel> { 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()); // , business logic. pipeline.addlast(new securechatserverhandler()); } } private static class securechatserverhandler extends simplechannelinboundhandler<string> { static final channelgroup channels = new defaultchannelgroup(globaleventexecutor.instance); @override public void channelactive(final channelhandlercontext ctx) { // 1 time session secured, send greeting , register channel global channel // list channel received messages others. ctx.pipeline().get(sslhandler.class).handshakefuture().addlistener( new genericfuturelistener<future<channel>>() { @override public void operationcomplete(future<channel> future) throws exception { ctx.writeandflush( "welcome " + inetaddress.getlocalhost().gethostname() + " secure chat service!\n"); ctx.writeandflush( "your session protected " + 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 received message channels current one. (channel c : channels) { if (c != ctx.channel()) { c.writeandflush("[" + ctx.channel().remoteaddress() + "] " + msg + '\n'); } else { c.writeandflush("[you] " + msg + '\n'); } } // close connection if client has sent 'bye'. if ("bye".equals(msg.tolowercase())) { ctx.close(); } } @override public void exceptioncaught(channelhandlercontext ctx, throwable cause) { cause.printstacktrace(); ctx.close(); } } }

client 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 grouping = new nioeventloopgroup(); seek { bootstrap b = new bootstrap(); b.group(group) .channel(niosocketchannel.class) .handler(new securechatclientinitializer(engine)); // start connection attempt. channel ch = b.connect(host, port).sync().channel(); // read commands stdin. channelfuture lastwritefuture = null; bufferedreader in = new bufferedreader(new inputstreamreader(system.in)); (; ; ) { string line = in.readline(); if (line == null) { break; } // sends received line server. lastwritefuture = ch.writeandflush(line + "\r\n"); // if user typed 'bye' command, wait until server closes // connection. if ("bye".equals(line.tolowercase())) { ch.closefuture().sync(); break; } } // wait until messages flushed before closing channel. if (lastwritefuture != null) { lastwritefuture.sync(); } } { // connection closed automatically on shutdown. group.shutdowngracefully(); } } private static class securechatclientinitializer extends channelinitializer<socketchannel> { private final sslengine sslctx; public securechatclientinitializer(sslengine sslctx) { this.sslctx = sslctx; } @override public void initchannel(socketchannel ch) throws exception { channelpipeline pipeline = ch.pipeline(); // add together ssl handler first encrypt , decrypt everything. // in example, utilize bogus certificate in server side // , take invalid certificates in client side. // need more complicated identify both // , server in real world. //pipeline.addlast(sslctx.newhandler(ch.alloc(), securechatclient.host, securechatclient.port)); pipeline.addlast(new sslhandler(sslctx)); // on top of ssl handler, add together text line codec. pipeline.addlast(new delimiterbasedframedecoder(8192, delimiters.linedelimiter())); pipeline.addlast(new stringdecoder()); pipeline.addlast(new stringencoder()); //pipeline.addlast(new logginghandler(loglevel.info)); // , business logic. pipeline.addlast(new securechatclienthandler()); } } private static class securechatclienthandler extends simplechannelinboundhandler<string> { @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(); } } }

server exception:

info: [id: 0x5eb2ac7a, /0:0:0:0:0:0:0:0:8992] received: [id: 0x7d7a7dca, /127.0.0.1:55932 => /127.0.0.1:8992] io.netty.handler.codec.decoderexception: javax.net.ssl.sslhandshakeexception: ciphertext sanity check failed @ io.netty.handler.codec.bytetomessagedecoder.calldecode(bytetomessagedecoder.java:278) @ io.netty.handler.codec.bytetomessagedecoder.channelread(bytetomessagedecoder.java:147) @ io.netty.channel.abstractchannelhandlercontext.invokechannelread(abstractchannelhandlercontext.java:333) @ io.netty.channel.abstractchannelhandlercontext.firechannelread(abstractchannelhandlercontext.java:319) @ io.netty.channel.defaultchannelpipeline.firechannelread(defaultchannelpipeline.java:787) @ io.netty.channel.nio.abstractniobytechannel$niobyteunsafe.read(abstractniobytechannel.java:130) @ io.netty.channel.nio.nioeventloop.processselectedkey(nioeventloop.java:511) @ io.netty.channel.nio.nioeventloop.processselectedkeysoptimized(nioeventloop.java:468) @ io.netty.channel.nio.nioeventloop.processselectedkeys(nioeventloop.java:382) @ io.netty.channel.nio.nioeventloop.run(nioeventloop.java:354) @ io.netty.util.concurrent.singlethreadeventexecutor$2.run(singlethreadeventexecutor.java:116) @ io.netty.util.concurrent.defaultthreadfactory$defaultrunnabledecorator.run(defaultthreadfactory.java:137) @ java.lang.thread.run(thread.java:744) caused by: javax.net.ssl.sslhandshakeexception: ciphertext sanity check failed @ sun.security.ssl.alerts.getsslexception(alerts.java:192) @ sun.security.ssl.sslengineimpl.fatal(sslengineimpl.java:1683) @ sun.security.ssl.sslengineimpl.readrecord(sslengineimpl.java:959) @ sun.security.ssl.sslengineimpl.readnetrecord(sslengineimpl.java:884) @ sun.security.ssl.sslengineimpl.unwrap(sslengineimpl.java:758) @ javax.net.ssl.sslengine.unwrap(sslengine.java:624) @ io.netty.handler.ssl.sslhandler.unwrap(sslhandler.java:995) @ io.netty.handler.ssl.sslhandler.unwrap(sslhandler.java:921) @ io.netty.handler.ssl.sslhandler.decode(sslhandler.java:867) @ io.netty.handler.codec.bytetomessagedecoder.calldecode(bytetomessagedecoder.java:247) ... 12 more caused by: javax.crypto.badpaddingexception: ciphertext sanity check failed @ sun.security.ssl.inputrecord.decrypt(inputrecord.java:147) @ sun.security.ssl.engineinputrecord.decrypt(engineinputrecord.java:192) @ sun.security.ssl.sslengineimpl.readrecord(sslengineimpl.java:953) ... 19 more

client exception:

io.netty.handler.codec.decoderexception: javax.net.ssl.sslexception: received fatal alert: <unknown alert: 170> @ io.netty.handler.codec.bytetomessagedecoder.calldecode(bytetomessagedecoder.java:278) @ io.netty.handler.codec.bytetomessagedecoder.channelread(bytetomessagedecoder.java:147) @ io.netty.channel.abstractchannelhandlercontext.invokechannelread(abstractchannelhandlercontext.java:333) @ io.netty.channel.abstractchannelhandlercontext.firechannelread(abstractchannelhandlercontext.java:319) @ io.netty.channel.defaultchannelpipeline.firechannelread(defaultchannelpipeline.java:787) @ io.netty.channel.nio.abstractniobytechannel$niobyteunsafe.read(abstractniobytechannel.java:130) @ io.netty.channel.nio.nioeventloop.processselectedkey(nioeventloop.java:511) @ io.netty.channel.nio.nioeventloop.processselectedkeysoptimized(nioeventloop.java:468) @ io.netty.channel.nio.nioeventloop.processselectedkeys(nioeventloop.java:382) @ io.netty.channel.nio.nioeventloop.run(nioeventloop.java:354) @ io.netty.util.concurrent.singlethreadeventexecutor$2.run(singlethreadeventexecutor.java:116) @ io.netty.util.concurrent.defaultthreadfactory$defaultrunnabledecorator.run(defaultthreadfactory.java:137) @ java.lang.thread.run(thread.java:744) caused by: javax.net.ssl.sslexception: received fatal alert: <unknown alert: 170> @ sun.security.ssl.alerts.getsslexception(alerts.java:208) @ sun.security.ssl.sslengineimpl.fatal(sslengineimpl.java:1619) @ sun.security.ssl.sslengineimpl.fatal(sslengineimpl.java:1587) @ sun.security.ssl.sslengineimpl.recvalert(sslengineimpl.java:1756) @ sun.security.ssl.sslengineimpl.readrecord(sslengineimpl.java:1060) @ sun.security.ssl.sslengineimpl.readnetrecord(sslengineimpl.java:884) @ sun.security.ssl.sslengineimpl.unwrap(sslengineimpl.java:758) @ javax.net.ssl.sslengine.unwrap(sslengine.java:624) @ io.netty.handler.ssl.sslhandler.unwrap(sslhandler.java:995) @ io.netty.handler.ssl.sslhandler.unwrap(sslhandler.java:921) @ io.netty.handler.ssl.sslhandler.decode(sslhandler.java:867) @ io.netty.handler.codec.bytetomessagedecoder.calldecode(bytetomessagedecoder.java:247) ... 12 more

can explain why initializing server sslcontext trust mill not supplying key mill client sslcontext initialization method?

are attempting mutual authentication? if need phone call sslengine.setneedclientauth(true).

have seen sslcontext.java? may able simplify initialization process , alleviate need build own sslcontext objects. if certificates x509 , keys in pkcs#8 format don't have worry trust manager or key managers because sslcontext can read these , initialize (via newclientcontext , newservercontext). these interfaces back upwards mutual authentication if needed.

java ssl client netty server

Comments

Popular posts from this blog

c - Compilation of a code: unkown type name string -

java - Bypassing "final local variable defined in an enclosing type" -

json - Hibernate and Jackson (java.lang.IllegalStateException: Cannot call sendError() after the response has been committed) -