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