Top Description Inners Fields Constructors Methods
io.netty.handler.ssl

public Class SslHandler

extends ByteToMessageDecoder
implements ChannelOutboundHandler
Class Inheritance
All Implemented Interfaces
io.netty.channel.ChannelOutboundHandler, io.netty.channel.ChannelHandler
Imports
io.netty.buffer.ByteBuf, .ByteBufAllocator, .ByteBufUtil, .CompositeByteBuf, .Unpooled, io.netty.channel.AbstractCoalescingBufferQueue, .Channel, .ChannelConfig, .ChannelException, .ChannelFuture, .ChannelFutureListener, .ChannelHandlerContext, .ChannelInboundHandler, .ChannelOption, .ChannelOutboundBuffer, .ChannelOutboundHandler, .ChannelPipeline, .ChannelPromise, io.netty.channel.unix.UnixChannel, io.netty.handler.codec.ByteToMessageDecoder, .DecoderException, .UnsupportedMessageTypeException, io.netty.util.ReferenceCountUtil, io.netty.util.concurrent.DefaultPromise, .EventExecutor, .Future, .FutureListener, .ImmediateExecutor, .Promise, .PromiseNotifier, io.netty.util.internal.ObjectUtil, .PlatformDependent, .ThrowableUtil, .UnstableApi, io.netty.util.internal.logging.InternalLogger, .InternalLoggerFactory, java.io.IOException, java.net.SocketAddress, java.nio.ByteBuffer, java.nio.channels.ClosedChannelException, .DatagramChannel, .SocketChannel, java.util.List, java.util.concurrent.Executor, .RejectedExecutionException, .TimeUnit, java.util.regex.Pattern, javax.net.ssl.SSLEngine, .SSLEngineResult, .SSLEngineResult.HandshakeStatus, .SSLEngineResult.Status, .SSLException, .SSLHandshakeException, .SSLSession

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

Beside using the handshake ChannelFuture to get notified about the completion of the handshake it's also possible to detect it by implement the ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object) method and check for a SslHandshakeCompletionEvent.

Handshake

The handshake will be automatically issued for you once the Channel is active and SSLEngine#getUseClientMode() returns true. So no need to bother with it by your self.

Closing the session

To close the SSL session, the closeOutbound() 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.

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.

Nested and Inner Type Summary

Modifier and TypeClass and Description
private class
private class
private static enum
private class
SslHandler.SslHandlerCoalescingBufferQueue

Each call to SSL_write will introduce about ~100 bytes of overhead.

private class
SslHandler.SslTasksRunner

Runnable that will be scheduled on the delegatedTaskExecutor and will take care of resume work on the EventExecutor once the task was executed.

Field Summary

Modifier and TypeField and Description
private volatile long
private volatile long
private volatile ChannelHandlerContext
private final Executor
private final SSLEngine
private final SslHandler.SslEngineType
private Promise<Channel>
private volatile long
private static final Pattern
private static final Pattern
private final boolean
private static final InternalLogger
private static final int
MAX_PLAINTEXT_LENGTH

2^14 which is the maximum sized plaintext chunk allowed by the TLS RFC.

private int
private SslHandler.SslHandlerCoalescingBufferQueue
private final ByteBuffer[]
singleBuffer

Used if SSLEngine#wrap(ByteBuffer[], ByteBuffer) and SSLEngine#unwrap(ByteBuffer, ByteBuffer[]) should be called with a ByteBuf that is only backed by one ByteBuffer to reduce the object creation.

private final SslHandler.LazyChannelPromise
private final SslHandler.SslTasksRunner
private final SslHandler.SslTasksRunner
private final boolean
private short
private static final int
private static final int
STATE_FIRE_CHANNEL_READ

This flag is used to determine if we need to call ChannelHandlerContext#read() to consume more data when ChannelConfig#isAutoRead() is false.

private static final int
private static final int
private static final int
STATE_NEEDS_FLUSH

Set by wrap*() methods when something is produced.

private static final int
private static final int
private static final int
private static final int
private static final int
pack-priv volatile int
Inherited from io.netty.handler.codec.ByteToMessageDecoder:
COMPOSITE_CUMULATORMERGE_CUMULATOR

Constructor Summary

AccessConstructor and Description
public
SslHandler(SSLEngine
the SSLEngine this handler will use
engine
)

Creates a new instance which runs all delegated tasks directly on the EventExecutor.

public
SslHandler(SSLEngine
the SSLEngine this handler will use
engine
,
boolean
true if the first write request shouldn't be encrypted by the SSLEngine
startTls
)

Creates a new instance which runs all delegated tasks directly on the EventExecutor.

public
SslHandler(SSLEngine
the SSLEngine this handler will use
engine
,
Executor
the Executor that will be used to execute tasks that are returned by SSLEngine#getDelegatedTask().
delegatedTaskExecutor
)

Creates a new instance.

public
SslHandler(SSLEngine
the SSLEngine this handler will use
engine
,
boolean
true if the first write request shouldn't be encrypted by the SSLEngine
startTls
,
Executor
the Executor that will be used to execute tasks that are returned by SSLEngine#getDelegatedTask().
delegatedTaskExecutor
)

Creates a new instance.

Method Summary

Modifier and TypeMethod and Description
private static void
private ByteBuf
allocate(ChannelHandlerContext ctx, int capacity)

Always prefer a direct buffer when it's pooled, so that we reduce the number of memory copies in OpenSslEngine.

private ByteBuf
allocateOutNetBuf(ChannelHandlerContext ctx, int pendingBytes, int numComponents)

Allocates an outbound network buffer for SSLEngine#wrap(ByteBuffer, ByteBuffer) which can encrypt the specified amount of pending bytes.

public String

Returns:

the protocol name or null if application-level protocol has not been negotiated
applicationProtocol
()

Returns the name of the current application-level protocol.

private void
private static boolean
attemptCopyToCumulation(ByteBuf cumulation, ByteBuf next, int wrapDataSize)

public void
bind(ChannelHandlerContext
the ChannelHandlerContext for which the bind operation is made
ctx
,
SocketAddress
the SocketAddress to which it should bound
localAddress
,
ChannelPromise
the ChannelPromise to notify once the operation completes
promise
)

Implements io.netty.channel.ChannelOutboundHandler.bind.

Called once a bind operation is made.
public void
channelActive(final ChannelHandlerContext ctx)

Overrides io.netty.channel.ChannelInboundHandlerAdapter.channelActive.

Implements io.netty.channel.ChannelInboundHandler.channelActive.

Issues an initial TLS handshake once connected when used in client-mode
public void
public void
private void
private void
clearState(int bit)

public ChannelFuture
close()

Deprecated
Use closeOutbound()
public ChannelFuture
public void
close(final ChannelHandlerContext
the ChannelHandlerContext for which the close operation is made
ctx
,
final ChannelPromise
the ChannelPromise to notify once the operation completes
promise
)

Implements io.netty.channel.ChannelOutboundHandler.close.

Called once a close operation is made.
public ChannelFuture
closeOutbound()

Sends an SSL close_notify message to the specified channel and destroys the underlying SSLEngine.

public ChannelFuture
closeOutbound(final ChannelPromise promise)

Sends an SSL close_notify message to the specified channel and destroys the underlying SSLEngine.

private void
private void
closeOutboundAndChannel(final ChannelHandlerContext ctx, final ChannelPromise promise, boolean disconnect)

public void
connect(ChannelHandlerContext
the ChannelHandlerContext for which the connect operation is made
ctx
,
SocketAddress
the SocketAddress to which it should connect
remoteAddress
,
SocketAddress
the SocketAddress which is used as source on connect
localAddress
,
ChannelPromise
the ChannelPromise to notify once the operation completes
promise
)

Implements io.netty.channel.ChannelOutboundHandler.connect.

Called once a connect operation is made.
protected void
decode(ChannelHandlerContext ctx, ByteBuf
the ByteBuf from which to read data
in
,
List<Object>
the List to which decoded messages should be added
out
)

Implements abstract io.netty.handler.codec.ByteToMessageDecoder.decode.

Decode the from one ByteBuf to an other.
private void
private void
public void
deregister(ChannelHandlerContext
the ChannelHandlerContext for which the close operation is made
ctx
,
ChannelPromise
the ChannelPromise to notify once the operation completes
promise
)

Implements io.netty.channel.ChannelOutboundHandler.deregister.

Called once a deregister operation is made from the current registered EventLoop.
public void
disconnect(final ChannelHandlerContext
the ChannelHandlerContext for which the disconnect operation is made
ctx
,
final ChannelPromise
the ChannelPromise to notify once the operation completes
promise
)

Implements io.netty.channel.ChannelOutboundHandler.disconnect.

Called once a disconnect operation is made.
public SSLEngine
engine()

Returns the SSLEngine which is used by this handler.

public void
private void
executeChannelRead(final ChannelHandlerContext ctx, final ByteBuf decodedOut)

private void
executeDelegatedTask(boolean inUnwrap)

private void
private void
public void
flush(ChannelHandlerContext
the ChannelHandlerContext for which the flush operation is made
ctx
)

Implements io.netty.channel.ChannelOutboundHandler.flush.

Called once a flush operation is made.
private void
private void
private void
public final long
getCloseNotifyFlushTimeoutMillis()

Gets the timeout for flushing the close_notify that was triggered by closing the Channel.

public final long
getCloseNotifyReadTimeoutMillis()

Gets the timeout (in ms) for receiving the response for the close_notify that was triggered by closing the Channel.

public long
public long
private SslHandler.SslTasksRunner
getTaskRunner(boolean inUnwrap)

public void
handlerAdded(final ChannelHandlerContext ctx)

Overrides io.netty.channel.ChannelHandlerAdapter.handlerAdded.

Implements io.netty.channel.ChannelHandler.handlerAdded.

Gets called after the ChannelHandler was added to the actual context and it's ready to handle events.
public void
handlerRemoved0(ChannelHandlerContext ctx)

Overrides io.netty.handler.codec.ByteToMessageDecoder.handlerRemoved0.

Gets called after the ByteToMessageDecoder was removed from the actual context and it doesn't handle events anymore.
private void
private void
handshake(boolean
Set to true if the outbound buffer should be flushed (written to the network) at the end. Set to false if the handshake will be flushed later, e.g. as part of TCP Fast Open connect.
flushAtEnd
)

Performs TLS (re)negotiation.

public Future<Channel>

Returns:

the Future for the initial TLS handshake if renegotiate() was not invoked. The Future for the most recent TLS renegotiation otherwise.
handshakeFuture
()

Returns a Future that will get notified once the current TLS handshake completes.

private boolean
ignoreException(Throwable t)

Checks if the given Throwable can be ignore and just "swallowed" When an ssl connection is closed a close_notify message is sent.

private static boolean
public static boolean

Returns:

encrypted true if the ByteBuf is encrypted, false otherwise.
isEncrypted
(ByteBuf
The ByteBuf to read from. Be aware that it must have at least 5 bytes to read, otherwise it will throw an IllegalArgumentException.
buffer
)

Returns true if the given ByteBuf is encrypted.

private boolean
isStateSet(int bit)

private static IllegalStateException
private void
public void
private void
private void
public Future<Channel>
renegotiate()

Performs TLS renegotiation.

public Future<Channel>
renegotiate(final Promise<Channel> promise)

Performs TLS renegotiation.

private void
renegotiateOnEventLoop(final Promise<Channel> newHandshakePromise)

private boolean
runDelegatedTasks(boolean inUnwrap)

Will either run the delegated task directly calling Runnable#run() and return true or will offload the delegated task using Executor#execute(Runnable) and return false.

private void
safeClose(final ChannelHandlerContext ctx, final ChannelFuture flushFuture, final ChannelPromise promise)

public final void
setCloseNotifyFlushTimeout(long closeNotifyFlushTimeout, TimeUnit unit)

Sets the timeout for flushing the close_notify that was triggered by closing the Channel.

public final void
public final void
setCloseNotifyReadTimeout(long closeNotifyReadTimeout, TimeUnit unit)

Sets the timeout for receiving the response for the close_notify that was triggered by closing the Channel.

public final void
public void
setCloseNotifyTimeout(long closeNotifyTimeout, TimeUnit unit)

public void
setCloseNotifyTimeoutMillis(long closeNotifyFlushTimeoutMillis)

private void
setHandshakeFailure(ChannelHandlerContext ctx, Throwable cause)

Notify all the handshake futures about the failure during the handshake.

private void
setHandshakeFailure(ChannelHandlerContext ctx, Throwable cause, boolean closeInbound, boolean notify, boolean alwaysFlushAndClose)

Notify all the handshake futures about the failure during the handshake.

private void
private boolean

Returns:

true if handshakePromise was set successfully and a SslHandshakeCompletionEvent was fired. false otherwise.
setHandshakeSuccess
()

Notify all the handshake futures about the successfully handshake

private boolean
public void
setHandshakeTimeout(long handshakeTimeout, TimeUnit unit)

public void
setHandshakeTimeoutMillis(long handshakeTimeoutMillis)

private void
private void
setState(int bit)

public final void
setWrapDataSize(int
the number of bytes which will be passed to each SSLEngine#wrap(ByteBuffer[], int, int, ByteBuffer) call.
wrapDataSize
)

Sets the number of bytes to pass to each SSLEngine#wrap(ByteBuffer[], int, int, ByteBuffer) call.

public Future<Channel>
sslCloseFuture()

Return the Future that will get notified if the inbound of the SSLEngine is closed.

private void
startHandshakeProcessing(boolean flushAtEnd)

private static ByteBuffer
toByteBuffer(ByteBuf out, int index, int len)

private int
unwrap(ChannelHandlerContext ctx, ByteBuf packet, int length)

Unwraps inbound SSL records.

private int
unwrapNonAppData(ChannelHandlerContext ctx)

Calls SSLEngine#unwrap(ByteBuffer, ByteBuffer) with an empty buffer to handle handshakes, etc.

private void
wrap(ChannelHandlerContext ctx, boolean inUnwrap)

private SSLEngineResult
wrap(ByteBufAllocator alloc, SSLEngine engine, ByteBuf in, ByteBuf out)

private void
private SSLEngineResult
private boolean
public void
write(final ChannelHandlerContext
the ChannelHandlerContext for which the write operation is made
ctx
,
Object
the message to write
msg
,
ChannelPromise
the ChannelPromise to notify once the operation completes
promise
)

Implements io.netty.channel.ChannelOutboundHandler.write.

Called once a write operation is made.
Inherited from io.netty.handler.codec.ByteToMessageDecoder:
actualReadableBytescallDecodechannelReaddecodeLastdiscardSomeReadByteshandlerRemovedinternalBufferisSingleDecodesetCumulatorsetDiscardAfterReadssetSingleDecodeuserEventTriggered