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

public Class SslHandler

extends ByteToMessageDecoder
Class Inheritance
Imports
io.netty5.buffer.BufferUtil, .Buffer, .BufferAllocator, .CompositeBuffer, .DefaultBufferAllocators, .StandardAllocationTypes, io.netty5.channel.ChannelOutboundInvoker, .ReadBufferAllocator, .AbstractCoalescingBufferQueue, .Channel, .ChannelException, .ChannelHandler, .ChannelHandlerContext, .ChannelOption, .ChannelPipeline, io.netty5.util.Resource, io.netty5.channel.unix.UnixChannel, io.netty5.handler.codec.ByteToMessageDecoder, .DecoderException, .UnsupportedMessageTypeException, io.netty5.util.concurrent.DefaultPromise, .EventExecutor, .Future, .ImmediateEventExecutor, .ImmediateExecutor, .Promise, io.netty5.util.internal.PlatformDependent, .SilentDispose, .UnstableApi, io.netty5.util.internal.logging.InternalLogger, .InternalLoggerFactory, javax.net.ssl.SSLEngine, .SSLEngineResult, .SSLEngineResult.HandshakeStatus, .SSLEngineResult.Status, .SSLException, .SSLHandshakeException, .SSLSession, java.io.IOException, java.nio.ByteBuffer, java.nio.channels.ClosedChannelException, .DatagramChannel, .SocketChannel, java.util.concurrent.Executor, .RejectedExecutionException, .TimeUnit, java.util.regex.Pattern

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 Future to get notified about the completion of the handshake it's also possible to detect it by implement the ChannelHandler#channelInboundEvent(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 final EngineWrapper
engineWrapper

Used for converting Buffers into ByteBuffers, in a way that meet the expectations of the configured SSLEngine, and then calling the most optimal wrap and unwrap methods.

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 Promise<Channel>
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 ChannelOutboundInvoker#read(ReadBufferAllocator) to consume more data when ChannelOption#AUTO_READ 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.netty5.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 Buffer
allocate(ChannelHandlerContext ctx, int capacity)

Allocate buffer of the right direct/not-direct type that the SSLEngine prefers.

private Buffer
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
public void
channelActive(final ChannelHandlerContext ctx)

Overrides default io.netty5.channel.ChannelHandler.channelActive.

Issues an initial TLS handshake once connected when used in client-mode
public void
channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause)

Overrides default io.netty5.channel.ChannelHandler.channelExceptionCaught.

Gets called if a Throwable was thrown when handling inbound events.
public void
channelInactive(ChannelHandlerContext ctx)

Overrides io.netty5.handler.codec.ByteToMessageDecoder.channelInactive.

Overrides default io.netty5.channel.ChannelHandler.channelInactive.

The Channel of the ChannelHandlerContext was registered is now inactive and reached its end of lifetime.
public void
private void
private void
clearState(int bit)

public Future<Void>
close(final ChannelHandlerContext
the ChannelHandlerContext for which the close operation is made
ctx
)

Overrides default io.netty5.channel.ChannelHandler.close.

Called once a close operation is made.
public Future<Void>
closeOutbound()

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

private void
private Future<Void>
closeOutboundAndChannel(final ChannelHandlerContext ctx, boolean disconnect)

protected void
decode(ChannelHandlerContext ctx, Buffer
the Buffer from which to read data
in
)

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

Decode the from one Buffer to another.
private void
private void
public Future<Void>
disconnect(final ChannelHandlerContext
the ChannelHandlerContext for which the disconnect operation is made
ctx
)

Overrides default io.netty5.channel.ChannelHandler.disconnect.

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

Returns the SSLEngine which is used by this handler.

private static void
executeChannelRead(final ChannelHandlerContext ctx, final Buffer decodedOut)

private void
executeDelegatedTask(boolean inUnwrap)

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

Overrides default io.netty5.channel.ChannelHandler.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
public void
handlerRemoved0(ChannelHandlerContext ctx)

Overrides io.netty5.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 Buffer is encrypted, false otherwise.
isEncrypted
(Buffer
The Buffer 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 Buffer is encrypted.

private boolean
isStateSet(int bit)

private static IllegalStateException
private void
public long
pendingOutboundBytes(ChannelHandlerContext
the ChannelHandlerContext for which the operation is made.
ctx
)

Overrides default io.netty5.channel.ChannelHandler.pendingOutboundBytes.

The number of the outbound bytes that are buffered / queued in this ChannelHandler.
public void
read(ChannelHandlerContext
the ChannelHandlerContext for which the read operation is made
ctx
,
ReadBufferAllocator
The ReadBufferAllocator that should be used to allocate a Buffer if needed (for reading the data).
readBufferAllocator
)

Overrides default io.netty5.channel.ChannelHandler.read.

Called once a read operation is made from the current registered EventLoop.
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 Future<Void> flushFuture, final Promise<Void> 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 int
unwrap(ChannelHandlerContext ctx, Buffer packet, int length)

Unwraps inbound SSL records.

private int
unwrapNonAppData(ChannelHandlerContext ctx)

Calls SSLEngine#unwrap(ByteBuffer, ByteBuffer) with a null buffer to handle handshakes, etc.

private void
wrap(ChannelHandlerContext ctx, boolean inUnwrap)

private SSLEngineResult
wrap(SSLEngine engine, Buffer in, Buffer out)

private void
private boolean
public Future<Void>
write(final ChannelHandlerContext
the ChannelHandlerContext for which the write operation is made
ctx
,
Object
the message to write
msg
)

Overrides default io.netty5.channel.ChannelHandler.write.

Called once a write operation is made.
Inherited from io.netty5.handler.codec.ByteToMessageDecoder:
actualReadableByteschannelReadchannelShutdowndecodeLastdiscardSomeReadByteshandlerAddedhandlerRemovedinternalBufferisSharableisSingleDecodesetSingleDecode