- java.lang.Object
-
- io.netty5.channel.ChannelHandlerAdapter
-
- io.netty5.handler.codec.ByteToMessageDecoder
-
- io.netty5.handler.ssl.SslHandler
-
- All Implemented Interfaces:
ChannelHandler
public class SslHandler extends ByteToMessageDecoder
Adds SSL · TLS and StartTLS support to aChannel. Please refer to the "SecureChat" example in the distribution or the web site for the detailed usage.Beginning the handshake
Beside using the handshake
Futureto get notified about the completion of the handshake it's also possible to detect it by implement theChannelHandler.channelInboundEvent(ChannelHandlerContext, Object)method and check for aSslHandshakeCompletionEvent.Handshake
The handshake will be automatically issued for you once the
Channelis active andSSLEngine.getUseClientMode()returnstrue. 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 theclose_notifymessage to the remote peer. One exception is when you close theChannel-SslHandlerintercepts the close request and send theclose_notifymessage before the channel closure automatically. Once the SSL session is closed, it is not reusable, and consequently you should create a newSslHandlerwith a newSSLEngineas explained in the following section.Restarting the session
To restart the SSL session, you must remove the existing closed
SslHandlerfrom theChannelPipeline, insert a newSslHandlerwith a newSSLEngineinto 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:
- Client sends a StartTLS request to server.
- Server sends a StartTLS response to client.
- Client begins SSL handshake.
- create a new
SslHandlerinstance withstartTlsflag set totrue, - insert the
SslHandlerto theChannelPipeline, and - write a StartTLS response.
SslHandlerbefore sending the StartTLS response. Otherwise the client can send begin SSL handshake beforeSslHandleris inserted to theChannelPipeline, causing data corruption.The client-side implementation is much simpler.
- Write a StartTLS request,
- wait for the StartTLS response,
- create a new
SslHandlerinstance withstartTlsflag set tofalse, - insert the
SslHandlerto theChannelPipeline, and - 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 Class Summary
-
Nested classes/interfaces inherited from class io.netty5.handler.codec.ByteToMessageDecoder
ByteToMessageDecoder.Cumulator
-
-
Field Summary
-
Fields inherited from class io.netty5.handler.codec.ByteToMessageDecoder
COMPOSITE_CUMULATOR, MERGE_CUMULATOR
-
-
Constructor Summary
Constructors Constructor Description SslHandler(SSLEngine engine)Creates a new instance which runs all delegated tasks directly on theEventExecutor.SslHandler(SSLEngine engine, boolean startTls)Creates a new instance which runs all delegated tasks directly on theEventExecutor.SslHandler(SSLEngine engine, boolean startTls, Executor delegatedTaskExecutor)Creates a new instance.SslHandler(SSLEngine engine, Executor delegatedTaskExecutor)Creates a new instance.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Deprecated Methods Modifier and Type Method Description StringapplicationProtocol()Returns the name of the current application-level protocol.voidchannelActive(ChannelHandlerContext ctx)Issues an initial TLS handshake once connected when used in client-modevoidchannelExceptionCaught(ChannelHandlerContext ctx, Throwable cause)Gets called if aThrowablewas thrown when handling inbound events.voidchannelInactive(ChannelHandlerContext ctx)TheChannelof theChannelHandlerContextwas registered is now inactive and reached its end of lifetime.voidchannelReadComplete(ChannelHandlerContext ctx)Invoked when the last message read by the current read operation has been consumed byChannelHandler.channelRead(ChannelHandlerContext, Object).Future<Void>close(ChannelHandlerContext ctx)Called once a close operation is made.Future<Void>closeOutbound()Sends an SSLclose_notifymessage to the specified channel and destroys the underlyingSSLEngine.protected voiddecode(ChannelHandlerContext ctx, Buffer in)Decode the from oneBufferto another.Future<Void>disconnect(ChannelHandlerContext ctx)Called once a disconnect operation is made.SSLEngineengine()Returns theSSLEnginewhich is used by this handler.voidflush(ChannelHandlerContext ctx)Called once a flush operation is made.longgetCloseNotifyFlushTimeoutMillis()Gets the timeout for flushing the close_notify that was triggered by closing theChannel.longgetCloseNotifyReadTimeoutMillis()Gets the timeout (in ms) for receiving the response for the close_notify that was triggered by closing theChannel.longgetCloseNotifyTimeoutMillis()Deprecated.longgetHandshakeTimeoutMillis()voidhandlerAdded0(ChannelHandlerContext ctx)voidhandlerRemoved0(ChannelHandlerContext ctx)Gets called after theByteToMessageDecoderwas removed from the actual context and it doesn't handle events anymore.Future<Channel>handshakeFuture()Returns aFuturethat will get notified once the current TLS handshake completes.static booleanisEncrypted(Buffer buffer)Returnstrueif the givenBufferis encrypted.longpendingOutboundBytes(ChannelHandlerContext ctx)The number of the outbound bytes that are buffered / queued in thisChannelHandler.voidread(ChannelHandlerContext ctx)InterceptsChannelHandlerContext.read().Future<Channel>renegotiate()Performs TLS renegotiation.Future<Channel>renegotiate(Promise<Channel> promise)Performs TLS renegotiation.voidsetCloseNotifyFlushTimeout(long closeNotifyFlushTimeout, TimeUnit unit)Sets the timeout for flushing the close_notify that was triggered by closing theChannel.voidsetCloseNotifyFlushTimeoutMillis(long closeNotifyFlushTimeoutMillis)voidsetCloseNotifyReadTimeout(long closeNotifyReadTimeout, TimeUnit unit)Sets the timeout for receiving the response for the close_notify that was triggered by closing theChannel.voidsetCloseNotifyReadTimeoutMillis(long closeNotifyReadTimeoutMillis)voidsetCloseNotifyTimeout(long closeNotifyTimeout, TimeUnit unit)Deprecated.voidsetCloseNotifyTimeoutMillis(long closeNotifyFlushTimeoutMillis)Deprecated.voidsetHandshakeTimeout(long handshakeTimeout, TimeUnit unit)voidsetHandshakeTimeoutMillis(long handshakeTimeoutMillis)voidsetWrapDataSize(int wrapDataSize)Sets the number of bytes to pass to eachSSLEngine.wrap(ByteBuffer[], int, int, ByteBuffer)call.Future<Channel>sslCloseFuture()Future<Void>write(ChannelHandlerContext ctx, Object msg)Called once a write operation is made.-
Methods inherited from class io.netty5.handler.codec.ByteToMessageDecoder
actualReadableBytes, channelRead, channelShutdown, decodeLast, discardSomeReadBytes, handlerAdded, handlerRemoved, internalBuffer, isSharable, isSingleDecode, setSingleDecode
-
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
-
Methods inherited from interface io.netty5.channel.ChannelHandler
bind, channelInboundEvent, channelRegistered, channelUnregistered, channelWritabilityChanged, connect, deregister, register, sendOutboundEvent, shutdown
-
-
-
-
Constructor Detail
-
SslHandler
public SslHandler(SSLEngine engine)
Creates a new instance which runs all delegated tasks directly on theEventExecutor.- Parameters:
engine- theSSLEnginethis handler will use
-
SslHandler
public SslHandler(SSLEngine engine, boolean startTls)
Creates a new instance which runs all delegated tasks directly on theEventExecutor.
-
SslHandler
public SslHandler(SSLEngine engine, Executor delegatedTaskExecutor)
Creates a new instance.- Parameters:
engine- theSSLEnginethis handler will usedelegatedTaskExecutor- theExecutorthat will be used to execute tasks that are returned bySSLEngine.getDelegatedTask().
-
SslHandler
public SslHandler(SSLEngine engine, boolean startTls, Executor delegatedTaskExecutor)
Creates a new instance.- Parameters:
engine- theSSLEnginethis handler will usestartTls-trueif the first write request shouldn't be encrypted by theSSLEnginedelegatedTaskExecutor- theExecutorthat will be used to execute tasks that are returned bySSLEngine.getDelegatedTask().
-
-
Method Detail
-
getHandshakeTimeoutMillis
public long getHandshakeTimeoutMillis()
-
setHandshakeTimeout
public void setHandshakeTimeout(long handshakeTimeout, TimeUnit unit)
-
setHandshakeTimeoutMillis
public void setHandshakeTimeoutMillis(long handshakeTimeoutMillis)
-
setWrapDataSize
@UnstableApi public final void setWrapDataSize(int wrapDataSize)
Sets the number of bytes to pass to eachSSLEngine.wrap(ByteBuffer[], int, int, ByteBuffer)call.This value will partition data which is passed to write
write(ChannelHandlerContext, Object). The partitioning will work as follows:- If
wrapDataSize <= 0then we will write each data chunk as is. - If
wrapDataSize > data sizethen we will attempt to aggregate multiple data chunks together. - If
wrapDataSize > data sizeElse ifwrapDataSize <= data sizethen we will divide the data into chunks ofwrapDataSizewhen writing.
If the
SSLEnginedoesn't support a gather wrap operation (e.g.SslProvider.OPENSSL) then aggregating data before wrapping can help reduce the ratio between TLS overhead vs data payload which will lead to better goodput. Writing fixed chunks of data can also help target the underlying transport's (e.g. TCP) frame size. Under lossy/congested network conditions this may help the peer get full TLS packets earlier and be able to do work sooner, as opposed to waiting for the all the pieces of the TLS packet to arrive.- Parameters:
wrapDataSize- the number of bytes which will be passed to eachSSLEngine.wrap(ByteBuffer[], int, int, ByteBuffer)call.
- If
-
getCloseNotifyTimeoutMillis
@Deprecated public long getCloseNotifyTimeoutMillis()
Deprecated.
-
setCloseNotifyTimeout
@Deprecated public void setCloseNotifyTimeout(long closeNotifyTimeout, TimeUnit unit)
Deprecated.
-
setCloseNotifyTimeoutMillis
@Deprecated public void setCloseNotifyTimeoutMillis(long closeNotifyFlushTimeoutMillis)
Deprecated.
-
getCloseNotifyFlushTimeoutMillis
public final long getCloseNotifyFlushTimeoutMillis()
-
setCloseNotifyFlushTimeout
public final void setCloseNotifyFlushTimeout(long closeNotifyFlushTimeout, TimeUnit unit)
-
setCloseNotifyFlushTimeoutMillis
public final void setCloseNotifyFlushTimeoutMillis(long closeNotifyFlushTimeoutMillis)
-
getCloseNotifyReadTimeoutMillis
public final long getCloseNotifyReadTimeoutMillis()
-
setCloseNotifyReadTimeout
public final void setCloseNotifyReadTimeout(long closeNotifyReadTimeout, TimeUnit unit)
-
setCloseNotifyReadTimeoutMillis
public final void setCloseNotifyReadTimeoutMillis(long closeNotifyReadTimeoutMillis)
-
applicationProtocol
public String applicationProtocol()
Returns the name of the current application-level protocol.- Returns:
- the protocol name or
nullif application-level protocol has not been negotiated
-
handshakeFuture
public Future<Channel> handshakeFuture()
Returns aFuturethat will get notified once the current TLS handshake completes.- Returns:
- the
Futurefor the initial TLS handshake ifrenegotiate()was not invoked. TheFuturefor the most recent TLS renegotiation otherwise.
-
closeOutbound
public Future<Void> closeOutbound()
Sends an SSLclose_notifymessage to the specified channel and destroys the underlyingSSLEngine. This will not close the underlyingChannel. If you want to also close theChanneluseChannel.close()orChannelOutboundInvoker.close()
-
sslCloseFuture
public Future<Channel> sslCloseFuture()
Return theFuturethat will get notified if the inbound of theSSLEngineis closed. This method will return the sameFutureall the time.- See Also:
SSLEngine
-
handlerRemoved0
public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception
Description copied from class:ByteToMessageDecoderGets called after theByteToMessageDecoderwas removed from the actual context and it doesn't handle events anymore.- Overrides:
handlerRemoved0in classByteToMessageDecoder- Throws:
Exception
-
disconnect
public Future<Void> disconnect(ChannelHandlerContext ctx)
Description copied from interface:ChannelHandlerCalled once a disconnect operation is made.- Parameters:
ctx- theChannelHandlerContextfor which the disconnect operation is made- Returns:
- the
Futurewhich will be notified once the operation completes.
-
close
public Future<Void> close(ChannelHandlerContext ctx)
Description copied from interface:ChannelHandlerCalled once a close operation is made.- Parameters:
ctx- theChannelHandlerContextfor which the close operation is made- Returns:
- the
Futurewhich will be notified once the operation completes.
-
read
public void read(ChannelHandlerContext ctx)
Description copied from interface:ChannelHandlerInterceptsChannelHandlerContext.read().
-
write
public Future<Void> write(ChannelHandlerContext ctx, Object msg)
Description copied from interface:ChannelHandlerCalled once a write operation is made. The write operation will write the messages through theChannelPipeline. Those are then ready to be flushed to the actualChannelonceChannel.flush()is called.- Parameters:
ctx- theChannelHandlerContextfor which the write operation is mademsg- the message to write- Returns:
- the
Futurewhich will be notified once the operation completes.
-
flush
public void flush(ChannelHandlerContext ctx)
Description copied from interface:ChannelHandlerCalled once a flush operation is made. The flush operation will try to flush out all previous written messages that are pending.- Parameters:
ctx- theChannelHandlerContextfor which the flush operation is made
-
channelInactive
public void channelInactive(ChannelHandlerContext ctx) throws Exception
Description copied from interface:ChannelHandlerTheChannelof theChannelHandlerContextwas registered is now inactive and reached its end of lifetime.- Specified by:
channelInactivein interfaceChannelHandler- Overrides:
channelInactivein classByteToMessageDecoder- Throws:
Exception
-
channelExceptionCaught
public void channelExceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
Description copied from interface:ChannelHandlerGets called if aThrowablewas thrown when handling inbound events.- Throws:
Exception
-
isEncrypted
public static boolean isEncrypted(Buffer buffer)
Returnstrueif the givenBufferis encrypted. Be aware that this method will not increase the readerIndex of the givenBuffer.- Parameters:
buffer- TheBufferto read from. Be aware that it must have at least 5 bytes to read, otherwise it will throw anIllegalArgumentException.- Returns:
- encrypted
trueif theBufferis encrypted,falseotherwise. - Throws:
IllegalArgumentException- Is thrown if the givenBufferhas not at least 5 bytes to read.
-
decode
protected void decode(ChannelHandlerContext ctx, Buffer in) throws SSLException
Description copied from class:ByteToMessageDecoderDecode the from oneBufferto another. This method will be called till either the inputBufferhas nothing to read when return from this method or till nothing was read from the inputBuffer.- Specified by:
decodein classByteToMessageDecoder- Parameters:
ctx- theChannelHandlerContextwhich thisByteToMessageDecoderbelongs toin- theBufferfrom which to read data- Throws:
SSLException
-
channelReadComplete
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception
Description copied from interface:ChannelHandlerInvoked when the last message read by the current read operation has been consumed byChannelHandler.channelRead(ChannelHandlerContext, Object). IfChannelOption.AUTO_READis off, no further attempt to read an inbound data from the currentChannelwill be made untilChannelHandlerContext.read()is called.- Specified by:
channelReadCompletein interfaceChannelHandler- Overrides:
channelReadCompletein classByteToMessageDecoder- Throws:
Exception
-
handlerAdded0
public void handlerAdded0(ChannelHandlerContext ctx) throws Exception
- Overrides:
handlerAdded0in classByteToMessageDecoder- Throws:
Exception
-
renegotiate
public Future<Channel> renegotiate(Promise<Channel> promise)
Performs TLS renegotiation.
-
channelActive
public void channelActive(ChannelHandlerContext ctx) throws Exception
Issues an initial TLS handshake once connected when used in client-mode- Throws:
Exception
-
pendingOutboundBytes
public long pendingOutboundBytes(ChannelHandlerContext ctx)
Description copied from interface:ChannelHandlerThe number of the outbound bytes that are buffered / queued in thisChannelHandler. This number will affect the writability of theChanneltogether the buffered / queued bytes in theChannelitself. By default this methods returns0. If theChannelHandlerimplementation buffers / queues outbound data this methods should be implemented to return the correct value.- Parameters:
ctx- theChannelHandlerContextfor which the operation is made.- Returns:
- the number of buffered / queued bytes.
-
-