Class SslHandler

All Implemented Interfaces:
ChannelDownstreamHandler, ChannelHandler, ChannelUpstreamHandler, LifeCycleAwareChannelHandler

public class SslHandler extends FrameDecoder implements ChannelDownstreamHandler
Adds SSL · TLS and StartTLS support to a Channel. Please refer to the "SecureChat" example in the distribution or the web site for the detailed usage.

Beginning the handshake

You must make sure not to write a message while the handshake is in progress unless you are renegotiating. You will be notified by the ChannelFuture which is returned by the handshake() method when the handshake process succeeds or fails.

Handshake

If isIssueHandshake() is false (default) you will need to take care of calling handshake() by your own. In most situations were SslHandler is used in 'client mode' you want to issue a handshake once the connection was established. if setIssueHandshake(boolean) is set to true you don't need to worry about this as the SslHandler will take care of it.

Renegotiation

If enableRenegotiation is true (default) and the initial handshake has been done successfully, you can call handshake() to trigger the renegotiation.

If enableRenegotiation is false, an attempt to trigger renegotiation will result in the connection closure.

Please note that TLS renegotiation had a security issue before. If your runtime environment did not fix it, please make sure to disable TLS renegotiation by calling setEnableRenegotiation(boolean) with false. For more information, please refer to the following documents:

Closing the session

To close the SSL session, the close() method should be called to send the close_notify message to the remote peer. One exception is when you close the Channel - SslHandler intercepts the close request and send the close_notify message before the channel closure automatically. Once the SSL session is closed, it is not reusable, and consequently you should create a new SslHandler with a new SSLEngine as explained in the following section.

Restarting the session

To restart the SSL session, you must remove the existing closed SslHandler from the ChannelPipeline, insert a new SslHandler with a new SSLEngine into the pipeline, and start the handshake process as described in the first section.

Implementing StartTLS

StartTLS is the communication pattern that secures the wire in the middle of the plaintext connection. Please note that it is different from SSL · TLS, that secures the wire from the beginning of the connection. Typically, StartTLS is composed of three steps:

  1. Client sends a StartTLS request to server.
  2. Server sends a StartTLS response to client.
  3. Client begins SSL handshake.
If you implement a server, you need to:
  1. create a new SslHandler instance with startTls flag set to true,
  2. insert the SslHandler to the ChannelPipeline, and
  3. write a StartTLS response.
Please note that you must insert SslHandler before sending the StartTLS response. Otherwise the client can send begin SSL handshake before SslHandler is inserted to the ChannelPipeline, causing data corruption.

The client-side implementation is much simpler.

  1. Write a StartTLS request,
  2. wait for the StartTLS response,
  3. create a new SslHandler instance with startTls flag set to false,
  4. insert the SslHandler to the ChannelPipeline, and
  5. Initiate SSL handshake by calling handshake().

Known issues

Because of a known issue with the current implementation of the SslEngine that comes with Java it may be possible that you see blocked IO-Threads while a full GC is done.

So if you are affected you can workaround this problem by adjust the cache settings like shown below:

     SslContext context = ...;
     context.getServerSessionContext().setSessionCacheSize(someSaneSize);
     context.getServerSessionContext().setSessionTime(someSameTimeout);
 

What values to use here depends on the nature of your application and should be set based on monitoring and debugging of it. For more details see #832 in our issue tracker.

  • Field Details

    • logger

      private static final InternalLogger logger
    • EMPTY_BUFFER

      private static final ByteBuffer EMPTY_BUFFER
    • IGNORABLE_CLASS_IN_STACK

      private static final Pattern IGNORABLE_CLASS_IN_STACK
    • IGNORABLE_ERROR_MESSAGE

      private static final Pattern IGNORABLE_ERROR_MESSAGE
    • defaultBufferPool

      private static SslBufferPool defaultBufferPool
    • ctx

      private volatile ChannelHandlerContext ctx
    • engine

      private final SSLEngine engine
    • bufferPool

      private final SslBufferPool bufferPool
    • startTls

      private final boolean startTls
    • enableRenegotiation

      private volatile boolean enableRenegotiation
    • handshakeLock

      final Object handshakeLock
    • handshaking

      private boolean handshaking
    • handshaken

      private volatile boolean handshaken
    • handshakeFuture

      private volatile ChannelFuture handshakeFuture
    • sentFirstMessage

      private volatile int sentFirstMessage
    • sentCloseNotify

      private volatile int sentCloseNotify
    • closedOutboundAndChannel

      private volatile int closedOutboundAndChannel
    • SENT_FIRST_MESSAGE_UPDATER

      private static final AtomicIntegerFieldUpdater<SslHandler> SENT_FIRST_MESSAGE_UPDATER
    • SENT_CLOSE_NOTIFY_UPDATER

      private static final AtomicIntegerFieldUpdater<SslHandler> SENT_CLOSE_NOTIFY_UPDATER
    • CLOSED_OUTBOUND_AND_CHANNEL_UPDATER

      private static final AtomicIntegerFieldUpdater<SslHandler> CLOSED_OUTBOUND_AND_CHANNEL_UPDATER
    • ignoreClosedChannelException

      int ignoreClosedChannelException
    • ignoreClosedChannelExceptionLock

      final Object ignoreClosedChannelExceptionLock
    • pendingUnencryptedWrites

      private final Queue<SslHandler.PendingWrite> pendingUnencryptedWrites
    • pendingUnencryptedWritesLock

      private final NonReentrantLock pendingUnencryptedWritesLock
    • pendingEncryptedWrites

      private final Queue<MessageEvent> pendingEncryptedWrites
    • pendingEncryptedWritesLock

      private final NonReentrantLock pendingEncryptedWritesLock
    • issueHandshake

      private volatile boolean issueHandshake
    • writeBeforeHandshakeDone

      private volatile boolean writeBeforeHandshakeDone
    • sslEngineCloseFuture

      private final SslHandler.SSLEngineInboundCloseFuture sslEngineCloseFuture
    • closeOnSslException

      private boolean closeOnSslException
    • packetLength

      private int packetLength
    • timer

      private final Timer timer
    • handshakeTimeoutInMillis

      private final long handshakeTimeoutInMillis
    • handshakeTimeout

      private Timeout handshakeTimeout
  • Constructor Details

    • SslHandler

      public SslHandler(SSLEngine engine)
      Creates a new instance.
      Parameters:
      engine - the SSLEngine this handler will use
    • SslHandler

      public SslHandler(SSLEngine engine, SslBufferPool bufferPool)
      Creates a new instance.
      Parameters:
      engine - the SSLEngine this handler will use
      bufferPool - the SslBufferPool where this handler will acquire the buffers required by the SSLEngine
    • SslHandler

      public SslHandler(SSLEngine engine, boolean startTls)
      Creates a new instance.
      Parameters:
      engine - the SSLEngine this handler will use
      startTls - true if the first write request shouldn't be encrypted by the SSLEngine
    • SslHandler

      public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls)
      Creates a new instance.
      Parameters:
      engine - the SSLEngine this handler will use
      bufferPool - the SslBufferPool where this handler will acquire the buffers required by the SSLEngine
      startTls - true if the first write request shouldn't be encrypted by the SSLEngine
    • SslHandler

      public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls, Timer timer, long handshakeTimeoutInMillis)
      Creates a new instance.
      Parameters:
      engine - the SSLEngine this handler will use
      bufferPool - the SslBufferPool where this handler will acquire the buffers required by the SSLEngine
      startTls - true if the first write request shouldn't be encrypted by the SSLEngine
      timer - the Timer which will be used to process the timeout of the handshake(). Be aware that the given Timer will not get stopped automaticly, so it is up to you to cleanup once you not need it anymore
      handshakeTimeoutInMillis - the time in milliseconds after whic the handshake() will be failed, and so the future notified
  • Method Details