SSLException in SslHandler; based on SecureChat example
bwagner
bwagner at mpowertrading.com
Mon Apr 13 12:44:38 EDT 2009
We are using Netty in our client application so far with great success, the performance so far has been fantastic. We want to use the SslHandler for secure connections, and we have built our communication handlers based on the SecureChat demo provided with the Netty distribution. We are using the "fake" keystore as proof of concept. It works great about 99% of the time, but about 1% of the time we get the following stack trace thrown from the Sun SSLEngineImpl on the server:
11:49:46.406 [New I/O server worker #2-1] INFO session.netty.NettyHandler - client connected: sessionChannel=[data.core.session.netty.NettySessionChannel:session=[data.core.session.Session:id=100023,connectionTime=1239376195421,statusTime=1239376195421,connectionStatusType=CONNECTED,loginAttemptCount=0,localInetAddress=localhost/127.0.0.1,localHostName=localhost,localPort=9039,remoteInetAddress=localhost/127.0.0.1,remoteHostName=localhost,remotePort=2000,accountType=UNKNOWN,user=null,accountUserList=null],channel=NioAcceptedSocketChannel(id: 9093ef5d-0120-1000-9342-0188705af860, localhost/127.0.0.1:2000 => localhost/127.0.0.1:9039)]
false
11:49:46.468 [New I/O server worker #2-1] ERROR impl.session.SessionSocketManager - onException: sessionChannel=[data.core.session.netty.NettySessionChannel:session=[data.core.session.Session:id=100023,connectionTime=1239376195421,statusTime=1239376195421,connectionStatusType=CONNECTED,loginAttemptCount=0,localInetAddress=localhost/127.0.0.1,localHostName=localhost,localPort=9039,remoteInetAddress=localhost/127.0.0.1,remoteHostName=localhost,remotePort=2000,accountType=UNKNOWN,user=null,accountUserList=null],channel=NioAcceptedSocketChannel(id: 9093ef5d-0120-1000-9342-0188705af860, localhost/127.0.0.1:2000 => localhost/127.0.0.1:9039)]
javax.net.ssl.SSLException: Algorithm missing:
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.changeReadCiphers(SSLEngineImpl.java:532)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.readRecord(SSLEngineImpl.java:987)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.readNetRecord(SSLEngineImpl.java:793)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.unwrap(SSLEngineImpl.java:669)
at javax.net.ssl.SSLEngine.unwrap(SSLEngine.java:607)
at org.jboss.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:644)
at org.jboss.netty.handler.ssl.SslHandler.decode(SslHandler.java:398)
at org.jboss.netty.handler.codec.frame.FrameDecoder.callDecode(FrameDecoder.java:232)
at org.jboss.netty.handler.codec.frame.FrameDecoder.messageReceived(FrameDecoder.java:172)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:293)
at org.jboss.netty.channel.Channels.fireMessageReceived(Channels.java:280)
at org.jboss.netty.channel.socket.nio.NioWorker.readIntoHeapBuffer(NioWorker.java:300)
at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:254)
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:163)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.security.NoSuchAlgorithmException: Could not create cipher RC4/128
at com.sun.net.ssl.internal.ssl.CipherBox.<init>(CipherBox.java:93)
at com.sun.net.ssl.internal.ssl.CipherBox.newCipherBox(CipherBox.java:113)
at com.sun.net.ssl.internal.ssl.CipherSuite$BulkCipher.newCipher(CipherSuite.java:350)
at com.sun.net.ssl.internal.ssl.Handshaker.newReadCipher(Handshaker.java:356)
at com.sun.net.ssl.internal.ssl.SSLEngineImpl.changeReadCiphers(SSLEngineImpl.java:528)
... 16 more
Caused by: java.security.InvalidKeyException: No installed provider supports this key: (null)
at javax.crypto.Cipher.a(DashoA13*..)
at javax.crypto.Cipher.init(DashoA13*..)
at javax.crypto.Cipher.init(DashoA13*..)
at com.sun.net.ssl.internal.ssl.CipherBox.<init>(CipherBox.java:82)
... 20 more
I believe I'm following the examples very closely with regard to setup of the handlers and pipelines. This is my ChannelPipelineFactory:
public class ServerNettyPipelineFactory implements ChannelPipelineFactory {
protected INettySocket nettySocket; // the reference to the {@link INettySocket} instance
/**
* Creates a new {@link ClientNettyPipelineFactory}.
* @param nettySocket the reference to the {@link INettySocket} instance
*/
public ServerNettyPipelineFactory(INettySocket nettySocket) {
this.nettySocket = nettySocket;
}
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline channelPipeline = Channels.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 client
// and server in the real world.
SSLContext serverContext = ServerSecureSslContextFactory.getServerContext();
SSLEngine sslEngine = serverContext.createSSLEngine();
sslEngine.setUseClientMode(false);
channelPipeline.addLast("ssl", new SslHandler(sslEngine));
// add object decoder/encoder
channelPipeline.addLast("decoder", new ObjectDecoder());
channelPipeline.addLast("encoder", new ObjectEncoder());
// create a new {@link NettyHandler} instance for each new channel
NettyHandler nettyHandler = new ServerNettyHandler(this.nettySocket);
channelPipeline.addLast("handler", nettyHandler);
return channelPipeline;
}
}
This is my Server's SslContextFactory; you'll notice that I refactored the example to move the server context initialization from a static initializer block to singleton construction so that I can control the time of loading (seen in the next block below):
public class ServerSecureSslContextFactory {
private static final String PROTOCOL = "TLS";
private static SSLContext SERVER_CONTEXT = null;
private static final Object LOCK = new Object();
/**
* Creates the server SSL context.
*/
private static void createServerInstance() {
String algorithm = Security.getProperty("ssl.KeyManagerFactory.algorithm");
if (algorithm == null) {
algorithm = "SunX509";
}
SSLContext serverContext = null;
try {
InputStream keyStoreStream = SecureKeyStore.asInputStream();
char[] keyStorePassword = SecureKeyStore.getKeyStorePassword();
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(keyStoreStream, keyStorePassword);
// Set up key manager factory to use our key store
char[] certificatePassword = SecureKeyStore.getCertificatePassword();
KeyManagerFactory kmf = KeyManagerFactory.getInstance(algorithm);
kmf.init(ks, certificatePassword);
// Initialize the SSLContext to work with our key managers.
KeyManager[] keyManagers = kmf.getKeyManagers();
TrustManager[] trustManagers = SecureTrustManagerFactory.getTrustManagers();
SecureRandom secureRandom = null;
serverContext = SSLContext.getInstance(PROTOCOL);
serverContext.init(keyManagers, trustManagers, secureRandom);
}
catch (Exception e) {
throw new Error("Failed to initialize the server-side SSLContext", e);
}
SERVER_CONTEXT = serverContext;
if (SERVER_CONTEXT == null) {
throw new Error("Failed to initialize the server-side SSLContext: SERVER_CONTEXT=" + SERVER_CONTEXT);
}
}
/**
* Returns the singleton server-side SSL context.
* @return the singleton server-side SSL context
*/
public static SSLContext getServerContext() {
if (SERVER_CONTEXT == null) {
synchronized (LOCK) {
if (SERVER_CONTEXT == null) {
createServerInstance();
}
}
}
return SERVER_CONTEXT;
}
}
And this is the relevent snippet from the instantiation of my Netty server:
public class ServerNettySocket implements INettySocket {
...
protected ExecutorService bossExecutor; // the main executor service for the Netty {@link ChannelFactory}
protected ExecutorService workerExecutor; // the auxiliary executor service for the Netty {@link ChannelFactory}
protected ChannelFactory channelFactory; // the Netty factory for creating {@link Channel} instances
protected ChannelPipelineFactory channelPipelineFactory; // the factory used to bootstrap encoders and handlers with each {@link Channel} instance
protected ServerBootstrap serverBootstrap; // the Netty factory for bootstrapping {@link Channel} instances with the encoders and handlers of {@link NettyPipelineFactory}
/**
* Creates a new {@link ServerNettySocket}.
*/
public ServerNettySocket(ISessionSocketListener sessionSocketListener) {
ServerSecureSslContextFactory.getServerContext(); // make sure the SSL context is cached
this.sessionSocketListener = sessionSocketListener;
this.sessionChannelMap = new ConcurrentHashMap<Session, ISessionChannel>();
this.serverSessionChannel = null;
this.bossExecutor = Executors.newCachedThreadPool();
this.workerExecutor = Executors.newCachedThreadPool();
this.channelFactory = new NioServerSocketChannelFactory(bossExecutor, workerExecutor);
this.channelPipelineFactory = new ServerNettyPipelineFactory(this);
this.serverBootstrap = new ServerBootstrap(channelFactory);
serverBootstrap.setPipelineFactory(channelPipelineFactory);
serverBootstrap.setOption("child.tcpNoDelay", true);
serverBootstrap.setOption("child.keepAlive", true);
}
...
}
Am I missing something, or is this a problem that is addressed by 3.1.0 Beta? This is troublesome because it is a non-deterministic issue. I will try using the Beta version in the mean-time. Thanks!
--
View this message in context: http://n2.nabble.com/SSLException-in-SslHandler--based-on-SecureChat-example-tp2628574p2628574.html
Sent from the Netty User Group mailing list archive at Nabble.com.
More information about the netty-users
mailing list