View Javadoc
1   /*
2    * Copyright 2012 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.handler.ssl;
17  
18  import io.netty.buffer.ByteBuf;
19  import io.netty.buffer.ByteBufAllocator;
20  import io.netty.buffer.ByteBufUtil;
21  import io.netty.buffer.CompositeByteBuf;
22  import io.netty.buffer.Unpooled;
23  import io.netty.channel.Channel;
24  import io.netty.channel.ChannelConfig;
25  import io.netty.channel.ChannelException;
26  import io.netty.channel.ChannelFuture;
27  import io.netty.channel.ChannelFutureListener;
28  import io.netty.channel.ChannelHandlerContext;
29  import io.netty.channel.ChannelInboundHandler;
30  import io.netty.channel.ChannelOutboundHandler;
31  import io.netty.channel.ChannelPipeline;
32  import io.netty.channel.ChannelPromise;
33  import io.netty.channel.ChannelPromiseNotifier;
34  import io.netty.channel.PendingWriteQueue;
35  import io.netty.handler.codec.ByteToMessageDecoder;
36  import io.netty.handler.codec.UnsupportedMessageTypeException;
37  import io.netty.util.ReferenceCountUtil;
38  import io.netty.util.ReferenceCounted;
39  import io.netty.util.concurrent.DefaultPromise;
40  import io.netty.util.concurrent.EventExecutor;
41  import io.netty.util.concurrent.Future;
42  import io.netty.util.concurrent.FutureListener;
43  import io.netty.util.concurrent.ImmediateExecutor;
44  import io.netty.util.concurrent.Promise;
45  import io.netty.util.internal.PlatformDependent;
46  import io.netty.util.internal.ThrowableUtil;
47  import io.netty.util.internal.logging.InternalLogger;
48  import io.netty.util.internal.logging.InternalLoggerFactory;
49  
50  import java.io.IOException;
51  import java.net.SocketAddress;
52  import java.nio.ByteBuffer;
53  import java.nio.channels.ClosedChannelException;
54  import java.nio.channels.DatagramChannel;
55  import java.nio.channels.SocketChannel;
56  import java.util.ArrayList;
57  import java.util.List;
58  import java.util.concurrent.CountDownLatch;
59  import java.util.concurrent.Executor;
60  import java.util.concurrent.ScheduledFuture;
61  import java.util.concurrent.TimeUnit;
62  import java.util.regex.Pattern;
63  import javax.net.ssl.SSLEngine;
64  import javax.net.ssl.SSLEngineResult;
65  import javax.net.ssl.SSLEngineResult.HandshakeStatus;
66  import javax.net.ssl.SSLEngineResult.Status;
67  import javax.net.ssl.SSLException;
68  import javax.net.ssl.SSLSession;
69  
70  import static io.netty.handler.ssl.SslUtils.getEncryptedPacketLength;
71  
72  /**
73   * Adds <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security">SSL
74   * &middot; TLS</a> and StartTLS support to a {@link Channel}.  Please refer
75   * to the <strong>"SecureChat"</strong> example in the distribution or the web
76   * site for the detailed usage.
77   *
78   * <h3>Beginning the handshake</h3>
79   * <p>
80   * Beside using the handshake {@link ChannelFuture} to get notified about the completion of the handshake it's
81   * also possible to detect it by implement the
82   * {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)}
83   * method and check for a {@link SslHandshakeCompletionEvent}.
84   *
85   * <h3>Handshake</h3>
86   * <p>
87   * The handshake will be automatically issued for you once the {@link Channel} is active and
88   * {@link SSLEngine#getUseClientMode()} returns {@code true}.
89   * So no need to bother with it by your self.
90   *
91   * <h3>Closing the session</h3>
92   * <p>
93   * To close the SSL session, the {@link #close()} method should be
94   * called to send the {@code close_notify} message to the remote peer.  One
95   * exception is when you close the {@link Channel} - {@link SslHandler}
96   * intercepts the close request and send the {@code close_notify} message
97   * before the channel closure automatically.  Once the SSL session is closed,
98   * it is not reusable, and consequently you should create a new
99   * {@link SslHandler} with a new {@link SSLEngine} as explained in the
100  * following section.
101  *
102  * <h3>Restarting the session</h3>
103  * <p>
104  * To restart the SSL session, you must remove the existing closed
105  * {@link SslHandler} from the {@link ChannelPipeline}, insert a new
106  * {@link SslHandler} with a new {@link SSLEngine} into the pipeline,
107  * and start the handshake process as described in the first section.
108  *
109  * <h3>Implementing StartTLS</h3>
110  * <p>
111  * <a href="http://en.wikipedia.org/wiki/STARTTLS">StartTLS</a> is the
112  * communication pattern that secures the wire in the middle of the plaintext
113  * connection.  Please note that it is different from SSL &middot; TLS, that
114  * secures the wire from the beginning of the connection.  Typically, StartTLS
115  * is composed of three steps:
116  * <ol>
117  * <li>Client sends a StartTLS request to server.</li>
118  * <li>Server sends a StartTLS response to client.</li>
119  * <li>Client begins SSL handshake.</li>
120  * </ol>
121  * If you implement a server, you need to:
122  * <ol>
123  * <li>create a new {@link SslHandler} instance with {@code startTls} flag set
124  *     to {@code true},</li>
125  * <li>insert the {@link SslHandler} to the {@link ChannelPipeline}, and</li>
126  * <li>write a StartTLS response.</li>
127  * </ol>
128  * Please note that you must insert {@link SslHandler} <em>before</em> sending
129  * the StartTLS response.  Otherwise the client can send begin SSL handshake
130  * before {@link SslHandler} is inserted to the {@link ChannelPipeline}, causing
131  * data corruption.
132  * <p>
133  * The client-side implementation is much simpler.
134  * <ol>
135  * <li>Write a StartTLS request,</li>
136  * <li>wait for the StartTLS response,</li>
137  * <li>create a new {@link SslHandler} instance with {@code startTls} flag set
138  *     to {@code false},</li>
139  * <li>insert the {@link SslHandler} to the {@link ChannelPipeline}, and</li>
140  * <li>Initiate SSL handshake.</li>
141  * </ol>
142  *
143  * <h3>Known issues</h3>
144  * <p>
145  * Because of a known issue with the current implementation of the SslEngine that comes
146  * with Java it may be possible that you see blocked IO-Threads while a full GC is done.
147  * <p>
148  * So if you are affected you can workaround this problem by adjust the cache settings
149  * like shown below:
150  *
151  * <pre>
152  *     SslContext context = ...;
153  *     context.getServerSessionContext().setSessionCacheSize(someSaneSize);
154  *     context.getServerSessionContext().setSessionTime(someSameTimeout);
155  * </pre>
156  * <p>
157  * What values to use here depends on the nature of your application and should be set
158  * based on monitoring and debugging of it.
159  * For more details see
160  * <a href="https://github.com/netty/netty/issues/832">#832</a> in our issue tracker.
161  */
162 public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundHandler {
163 
164     private static final InternalLogger logger =
165             InternalLoggerFactory.getInstance(SslHandler.class);
166 
167     private static final Pattern IGNORABLE_CLASS_IN_STACK = Pattern.compile(
168             "^.*(?:Socket|Datagram|Sctp|Udt)Channel.*$");
169     private static final Pattern IGNORABLE_ERROR_MESSAGE = Pattern.compile(
170             "^.*(?:connection.*(?:reset|closed|abort|broken)|broken.*pipe).*$", Pattern.CASE_INSENSITIVE);
171 
172     /**
173      * Used in {@link #unwrapNonAppData(ChannelHandlerContext)} as input for
174      * {@link #unwrap(ChannelHandlerContext, ByteBuf, int,  int)}.  Using this static instance reduce object
175      * creation as {@link Unpooled#EMPTY_BUFFER#nioBuffer()} creates a new {@link ByteBuffer} everytime.
176      */
177     private static final SSLException SSLENGINE_CLOSED = ThrowableUtil.unknownStackTrace(
178             new SSLException("SSLEngine closed already"), SslHandler.class, "wrap(...)");
179     private static final SSLException HANDSHAKE_TIMED_OUT = ThrowableUtil.unknownStackTrace(
180             new SSLException("handshake timed out"), SslHandler.class, "handshake(...)");
181     private static final ClosedChannelException CHANNEL_CLOSED = ThrowableUtil.unknownStackTrace(
182             new ClosedChannelException(), SslHandler.class, "channelInactive(...)");
183 
184     private enum SslEngineType {
185         TCNATIVE(true, COMPOSITE_CUMULATOR) {
186             @Override
187             SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
188                     throws SSLException {
189                 int nioBufferCount = in.nioBufferCount();
190                 int writerIndex = out.writerIndex();
191                 final SSLEngineResult result;
192                 if (nioBufferCount > 1) {
193                     /*
194                      * If {@link OpenSslEngine} is in use,
195                      * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method
196                      * that accepts multiple {@link ByteBuffer}s without additional memory copies.
197                      */
198                     ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine;
199                     try {
200                         handler.singleBuffer[0] = toByteBuffer(out, writerIndex,
201                             out.writableBytes());
202                         result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), handler.singleBuffer);
203                     } finally {
204                         handler.singleBuffer[0] = null;
205                     }
206                 } else {
207                     result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
208                         toByteBuffer(out, writerIndex, out.writableBytes()));
209                 }
210                 out.writerIndex(writerIndex + result.bytesProduced());
211                 return result;
212             }
213 
214             @Override
215             int getPacketBufferSize(SslHandler handler) {
216                 return ((ReferenceCountedOpenSslEngine) handler.engine).maxEncryptedPacketLength0();
217             }
218 
219             @Override
220             int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) {
221                 return ((ReferenceCountedOpenSslEngine) handler.engine).calculateMaxLengthForWrap(pendingBytes,
222                                                                                                   numComponents);
223             }
224 
225             @Override
226             int calculatePendingData(SslHandler handler, int guess) {
227                 int sslPending = ((ReferenceCountedOpenSslEngine) handler.engine).sslPending();
228                 return sslPending > 0 ? sslPending : guess;
229             }
230 
231             @Override
232             boolean jdkCompatibilityMode(SSLEngine engine) {
233                 return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode;
234             }
235         },
236         CONSCRYPT(true, COMPOSITE_CUMULATOR) {
237             @Override
238             SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
239                     throws SSLException {
240                 int nioBufferCount = in.nioBufferCount();
241                 int writerIndex = out.writerIndex();
242                 final SSLEngineResult result;
243                 if (nioBufferCount > 1) {
244                     /*
245                      * Use a special unwrap method without additional memory copies.
246                      */
247                     try {
248                         handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes());
249                         result = ((ConscryptAlpnSslEngine) handler.engine).unwrap(
250                                 in.nioBuffers(readerIndex, len),
251                                 handler.singleBuffer);
252                     } finally {
253                         handler.singleBuffer[0] = null;
254                     }
255                 } else {
256                     result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
257                             toByteBuffer(out, writerIndex, out.writableBytes()));
258                 }
259                 out.writerIndex(writerIndex + result.bytesProduced());
260                 return result;
261             }
262 
263             @Override
264             int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) {
265                 return ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents);
266             }
267 
268             @Override
269             int calculatePendingData(SslHandler handler, int guess) {
270                 return guess;
271             }
272 
273             @Override
274             boolean jdkCompatibilityMode(SSLEngine engine) {
275                 return true;
276             }
277         },
278         JDK(false, MERGE_CUMULATOR) {
279             @Override
280             SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
281                     throws SSLException {
282                 int writerIndex = out.writerIndex();
283                 final SSLEngineResult result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
284                     toByteBuffer(out, writerIndex, out.writableBytes()));
285                 out.writerIndex(writerIndex + result.bytesProduced());
286                 return result;
287             }
288 
289             @Override
290             int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents) {
291                 return handler.engine.getSession().getPacketBufferSize();
292             }
293 
294             @Override
295             int calculatePendingData(SslHandler handler, int guess) {
296                 return guess;
297             }
298 
299             @Override
300             boolean jdkCompatibilityMode(SSLEngine engine) {
301                 return true;
302             }
303         };
304 
305         static SslEngineType forEngine(SSLEngine engine) {
306             return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE :
307                    engine instanceof ConscryptAlpnSslEngine ? CONSCRYPT : JDK;
308         }
309 
310         SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) {
311             this.wantsDirectBuffer = wantsDirectBuffer;
312             this.cumulator = cumulator;
313         }
314 
315         int getPacketBufferSize(SslHandler handler) {
316             return handler.engine.getSession().getPacketBufferSize();
317         }
318 
319         abstract SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
320                 throws SSLException;
321 
322         abstract int calculateWrapBufferCapacity(SslHandler handler, int pendingBytes, int numComponents);
323 
324         abstract int calculatePendingData(SslHandler handler, int guess);
325 
326         abstract boolean jdkCompatibilityMode(SSLEngine engine);
327 
328         // BEGIN Platform-dependent flags
329 
330         /**
331          * {@code true} if and only if {@link SSLEngine} expects a direct buffer.
332          */
333         final boolean wantsDirectBuffer;
334 
335         // END Platform-dependent flags
336 
337         /**
338          * When using JDK {@link SSLEngine}, we use {@link #MERGE_CUMULATOR} because it works only with
339          * one {@link ByteBuffer}.
340          *
341          * When using {@link OpenSslEngine}, we can use {@link #COMPOSITE_CUMULATOR} because it has
342          * {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} which works with multiple {@link ByteBuffer}s
343          * and which does not need to do extra memory copies.
344          */
345         final Cumulator cumulator;
346     }
347 
348     private volatile ChannelHandlerContext ctx;
349     private final SSLEngine engine;
350     private final SslEngineType engineType;
351     private final Executor delegatedTaskExecutor;
352     private final boolean jdkCompatibilityMode;
353 
354     /**
355      * Used if {@link SSLEngine#wrap(ByteBuffer[], ByteBuffer)} and {@link SSLEngine#unwrap(ByteBuffer, ByteBuffer[])}
356      * should be called with a {@link ByteBuf} that is only backed by one {@link ByteBuffer} to reduce the object
357      * creation.
358      */
359     private final ByteBuffer[] singleBuffer = new ByteBuffer[1];
360 
361     private final boolean startTls;
362     private boolean sentFirstMessage;
363     private boolean flushedBeforeHandshake;
364     private boolean readDuringHandshake;
365     private boolean handshakeStarted;
366     private PendingWriteQueue pendingUnencryptedWrites;
367 
368     private Promise<Channel> handshakePromise = new LazyChannelPromise();
369     private final LazyChannelPromise sslClosePromise = new LazyChannelPromise();
370 
371     /**
372      * Set by wrap*() methods when something is produced.
373      * {@link #channelReadComplete(ChannelHandlerContext)} will check this flag, clear it, and call ctx.flush().
374      */
375     private boolean needsFlush;
376 
377     private boolean outboundClosed;
378 
379     private int packetLength;
380 
381     /**
382      * This flag is used to determine if we need to call {@link ChannelHandlerContext#read()} to consume more data
383      * when {@link ChannelConfig#isAutoRead()} is {@code false}.
384      */
385     private boolean firedChannelRead;
386 
387     private volatile long handshakeTimeoutMillis = 10000;
388     private volatile long closeNotifyFlushTimeoutMillis = 3000;
389     private volatile long closeNotifyReadTimeoutMillis;
390 
391     /**
392      * Creates a new instance.
393      *
394      * @param engine  the {@link SSLEngine} this handler will use
395      */
396     public SslHandler(SSLEngine engine) {
397         this(engine, false);
398     }
399 
400     /**
401      * Creates a new instance.
402      *
403      * @param engine    the {@link SSLEngine} this handler will use
404      * @param startTls  {@code true} if the first write request shouldn't be
405      *                  encrypted by the {@link SSLEngine}
406      */
407     @SuppressWarnings("deprecation")
408     public SslHandler(SSLEngine engine, boolean startTls) {
409         this(engine, startTls, ImmediateExecutor.INSTANCE);
410     }
411 
412     /**
413      * @deprecated Use {@link #SslHandler(SSLEngine)} instead.
414      */
415     @Deprecated
416     public SslHandler(SSLEngine engine, Executor delegatedTaskExecutor) {
417         this(engine, false, delegatedTaskExecutor);
418     }
419 
420     /**
421      * @deprecated Use {@link #SslHandler(SSLEngine, boolean)} instead.
422      */
423     @Deprecated
424     public SslHandler(SSLEngine engine, boolean startTls, Executor delegatedTaskExecutor) {
425         if (engine == null) {
426             throw new NullPointerException("engine");
427         }
428         if (delegatedTaskExecutor == null) {
429             throw new NullPointerException("delegatedTaskExecutor");
430         }
431         this.engine = engine;
432         engineType = SslEngineType.forEngine(engine);
433         this.delegatedTaskExecutor = delegatedTaskExecutor;
434         this.startTls = startTls;
435         this.jdkCompatibilityMode = engineType.jdkCompatibilityMode(engine);
436         setCumulator(engineType.cumulator);
437     }
438 
439     public long getHandshakeTimeoutMillis() {
440         return handshakeTimeoutMillis;
441     }
442 
443     public void setHandshakeTimeout(long handshakeTimeout, TimeUnit unit) {
444         if (unit == null) {
445             throw new NullPointerException("unit");
446         }
447 
448         setHandshakeTimeoutMillis(unit.toMillis(handshakeTimeout));
449     }
450 
451     public void setHandshakeTimeoutMillis(long handshakeTimeoutMillis) {
452         if (handshakeTimeoutMillis < 0) {
453             throw new IllegalArgumentException(
454                     "handshakeTimeoutMillis: " + handshakeTimeoutMillis + " (expected: >= 0)");
455         }
456         this.handshakeTimeoutMillis = handshakeTimeoutMillis;
457     }
458 
459     /**
460      * @deprecated use {@link #getCloseNotifyFlushTimeoutMillis()}
461      */
462     @Deprecated
463     public long getCloseNotifyTimeoutMillis() {
464         return getCloseNotifyFlushTimeoutMillis();
465     }
466 
467     /**
468      * @deprecated use {@link #setCloseNotifyFlushTimeout(long, TimeUnit)}
469      */
470     @Deprecated
471     public void setCloseNotifyTimeout(long closeNotifyTimeout, TimeUnit unit) {
472         setCloseNotifyFlushTimeout(closeNotifyTimeout, unit);
473     }
474 
475     /**
476      * @deprecated use {@link #setCloseNotifyFlushTimeoutMillis(long)}
477      */
478     @Deprecated
479     public void setCloseNotifyTimeoutMillis(long closeNotifyFlushTimeoutMillis) {
480         setCloseNotifyFlushTimeoutMillis(closeNotifyFlushTimeoutMillis);
481     }
482 
483     /**
484      * Gets the timeout for flushing the close_notify that was triggered by closing the
485      * {@link Channel}. If the close_notify was not flushed in the given timeout the {@link Channel} will be closed
486      * forcibly.
487      */
488     public final long getCloseNotifyFlushTimeoutMillis() {
489         return closeNotifyFlushTimeoutMillis;
490     }
491 
492     /**
493      * Sets the timeout for flushing the close_notify that was triggered by closing the
494      * {@link Channel}. If the close_notify was not flushed in the given timeout the {@link Channel} will be closed
495      * forcibly.
496      */
497     public final void setCloseNotifyFlushTimeout(long closeNotifyFlushTimeout, TimeUnit unit) {
498         setCloseNotifyFlushTimeoutMillis(unit.toMillis(closeNotifyFlushTimeout));
499     }
500 
501     /**
502      * See {@link #setCloseNotifyFlushTimeout(long, TimeUnit)}.
503      */
504     public final void setCloseNotifyFlushTimeoutMillis(long closeNotifyFlushTimeoutMillis) {
505         if (closeNotifyFlushTimeoutMillis < 0) {
506             throw new IllegalArgumentException(
507                     "closeNotifyFlushTimeoutMillis: " + closeNotifyFlushTimeoutMillis + " (expected: >= 0)");
508         }
509         this.closeNotifyFlushTimeoutMillis = closeNotifyFlushTimeoutMillis;
510     }
511 
512     /**
513      * Gets the timeout (in ms) for receiving the response for the close_notify that was triggered by closing the
514      * {@link Channel}. This timeout starts after the close_notify message was successfully written to the
515      * remote peer. Use {@code 0} to directly close the {@link Channel} and not wait for the response.
516      */
517     public final long getCloseNotifyReadTimeoutMillis() {
518         return closeNotifyReadTimeoutMillis;
519     }
520 
521     /**
522      * Sets the timeout  for receiving the response for the close_notify that was triggered by closing the
523      * {@link Channel}. This timeout starts after the close_notify message was successfully written to the
524      * remote peer. Use {@code 0} to directly close the {@link Channel} and not wait for the response.
525      */
526     public final void setCloseNotifyReadTimeout(long closeNotifyReadTimeout, TimeUnit unit) {
527         setCloseNotifyReadTimeoutMillis(unit.toMillis(closeNotifyReadTimeout));
528     }
529 
530     /**
531      * See {@link #setCloseNotifyReadTimeout(long, TimeUnit)}.
532      */
533     public final void setCloseNotifyReadTimeoutMillis(long closeNotifyReadTimeoutMillis) {
534         if (closeNotifyReadTimeoutMillis < 0) {
535             throw new IllegalArgumentException(
536                     "closeNotifyReadTimeoutMillis: " + closeNotifyReadTimeoutMillis + " (expected: >= 0)");
537         }
538         this.closeNotifyReadTimeoutMillis = closeNotifyReadTimeoutMillis;
539     }
540 
541     /**
542      * Returns the {@link SSLEngine} which is used by this handler.
543      */
544     public SSLEngine engine() {
545         return engine;
546     }
547 
548     /**
549      * Returns the name of the current application-level protocol.
550      *
551      * @return the protocol name or {@code null} if application-level protocol has not been negotiated
552      */
553     public String applicationProtocol() {
554         SSLEngine engine = engine();
555         if (!(engine instanceof ApplicationProtocolAccessor)) {
556             return null;
557         }
558 
559         return ((ApplicationProtocolAccessor) engine).getNegotiatedApplicationProtocol();
560     }
561 
562     /**
563      * Returns a {@link Future} that will get notified once the current TLS handshake completes.
564      *
565      * @return the {@link Future} for the initial TLS handshake if {@link #renegotiate()} was not invoked.
566      *         The {@link Future} for the most recent {@linkplain #renegotiate() TLS renegotiation} otherwise.
567      */
568     public Future<Channel> handshakeFuture() {
569         return handshakePromise;
570     }
571 
572     /**
573      * Sends an SSL {@code close_notify} message to the specified channel and
574      * destroys the underlying {@link SSLEngine}.
575      *
576      * @deprecated use {@link Channel#close()} or {@link ChannelHandlerContext#close()}
577      */
578     @Deprecated
579     public ChannelFuture close() {
580         return close(ctx.newPromise());
581     }
582 
583     /**
584      * See {@link #close()}
585      *
586      * @deprecated use {@link Channel#close()} or {@link ChannelHandlerContext#close()}
587      */
588     @Deprecated
589     public ChannelFuture close(final ChannelPromise promise) {
590         final ChannelHandlerContext ctx = this.ctx;
591         ctx.executor().execute(new Runnable() {
592             @Override
593             public void run() {
594                 outboundClosed = true;
595                 engine.closeOutbound();
596                 try {
597                     flush(ctx, promise);
598                 } catch (Exception e) {
599                     if (!promise.tryFailure(e)) {
600                         logger.warn("{} flush() raised a masked exception.", ctx.channel(), e);
601                     }
602                 }
603             }
604         });
605 
606         return promise;
607     }
608 
609     /**
610      * Return the {@link Future} that will get notified if the inbound of the {@link SSLEngine} is closed.
611      *
612      * This method will return the same {@link Future} all the time.
613      *
614      * @see SSLEngine
615      */
616     public Future<Channel> sslCloseFuture() {
617         return sslClosePromise;
618     }
619 
620     @Override
621     public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
622         if (!pendingUnencryptedWrites.isEmpty()) {
623             // Check if queue is not empty first because create a new ChannelException is expensive
624             pendingUnencryptedWrites.removeAndFailAll(new ChannelException("Pending write on removal of SslHandler"));
625         }
626         pendingUnencryptedWrites = null;
627         if (engine instanceof ReferenceCounted) {
628             ((ReferenceCounted) engine).release();
629         }
630     }
631 
632     @Override
633     public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
634         ctx.bind(localAddress, promise);
635     }
636 
637     @Override
638     public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
639                         ChannelPromise promise) throws Exception {
640         ctx.connect(remoteAddress, localAddress, promise);
641     }
642 
643     @Override
644     public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
645         ctx.deregister(promise);
646     }
647 
648     @Override
649     public void disconnect(final ChannelHandlerContext ctx,
650                            final ChannelPromise promise) throws Exception {
651         closeOutboundAndChannel(ctx, promise, true);
652     }
653 
654     @Override
655     public void close(final ChannelHandlerContext ctx,
656                       final ChannelPromise promise) throws Exception {
657         closeOutboundAndChannel(ctx, promise, false);
658     }
659 
660     @Override
661     public void read(ChannelHandlerContext ctx) throws Exception {
662         if (!handshakePromise.isDone()) {
663             readDuringHandshake = true;
664         }
665 
666         ctx.read();
667     }
668 
669     private static IllegalStateException newPendingWritesNullException() {
670         return new IllegalStateException("pendingUnencryptedWrites is null, handlerRemoved0 called?");
671     }
672 
673     @Override
674     public void write(final ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
675         if (!(msg instanceof ByteBuf)) {
676             UnsupportedMessageTypeException exception = new UnsupportedMessageTypeException(msg, ByteBuf.class);
677             ReferenceCountUtil.safeRelease(msg);
678             promise.setFailure(exception);
679         } else if (pendingUnencryptedWrites == null) {
680             ReferenceCountUtil.safeRelease(msg);
681             promise.setFailure(newPendingWritesNullException());
682         } else {
683             pendingUnencryptedWrites.add(msg, promise);
684         }
685     }
686 
687     @Override
688     public void flush(ChannelHandlerContext ctx) throws Exception {
689         // Do not encrypt the first write request if this handler is
690         // created with startTLS flag turned on.
691         if (startTls && !sentFirstMessage) {
692             sentFirstMessage = true;
693             pendingUnencryptedWrites.removeAndWriteAll();
694             forceFlush(ctx);
695             return;
696         }
697 
698         try {
699             wrapAndFlush(ctx);
700         } catch (Throwable cause) {
701             setHandshakeFailure(ctx, cause);
702             PlatformDependent.throwException(cause);
703         }
704     }
705 
706     private void wrapAndFlush(ChannelHandlerContext ctx) throws SSLException {
707         if (pendingUnencryptedWrites.isEmpty()) {
708             // It's important to NOT use a voidPromise here as the user
709             // may want to add a ChannelFutureListener to the ChannelPromise later.
710             //
711             // See https://github.com/netty/netty/issues/3364
712             pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, ctx.newPromise());
713         }
714         if (!handshakePromise.isDone()) {
715             flushedBeforeHandshake = true;
716         }
717         try {
718             wrap(ctx, false);
719         } finally {
720             // We may have written some parts of data before an exception was thrown so ensure we always flush.
721             // See https://github.com/netty/netty/issues/3900#issuecomment-172481830
722             forceFlush(ctx);
723         }
724     }
725 
726     // This method will not call setHandshakeFailure(...) !
727     private void wrap(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLException {
728         ByteBuf out = null;
729         ChannelPromise promise = null;
730         ByteBufAllocator alloc = ctx.alloc();
731         boolean needUnwrap = false;
732         try {
733             // Only continue to loop if the handler was not removed in the meantime.
734             // See https://github.com/netty/netty/issues/5860
735             while (!ctx.isRemoved()) {
736                 Object msg = pendingUnencryptedWrites.current();
737                 if (msg == null) {
738                     break;
739                 }
740 
741                 ByteBuf buf = (ByteBuf) msg;
742                 if (out == null) {
743                     out = allocateOutNetBuf(ctx, buf.readableBytes(), buf.nioBufferCount());
744                 }
745 
746                 SSLEngineResult result = wrap(alloc, engine, buf, out);
747 
748                 if (result.getStatus() == Status.CLOSED) {
749                     // SSLEngine has been closed already.
750                     // Any further write attempts should be denied.
751                     pendingUnencryptedWrites.removeAndFailAll(SSLENGINE_CLOSED);
752                     return;
753                 } else {
754                     if (!buf.isReadable()) {
755                         promise = pendingUnencryptedWrites.remove();
756                     } else {
757                         promise = null;
758                     }
759 
760                     switch (result.getHandshakeStatus()) {
761                         case NEED_TASK:
762                             runDelegatedTasks();
763                             break;
764                         case FINISHED:
765                             setHandshakeSuccess();
766                             // deliberate fall-through
767                         case NOT_HANDSHAKING:
768                             setHandshakeSuccessIfStillHandshaking();
769                             // deliberate fall-through
770                         case NEED_WRAP:
771                             finishWrap(ctx, out, promise, inUnwrap, false);
772                             promise = null;
773                             out = null;
774                             break;
775                         case NEED_UNWRAP:
776                             needUnwrap = true;
777                             return;
778                         default:
779                             throw new IllegalStateException(
780                                     "Unknown handshake status: " + result.getHandshakeStatus());
781                     }
782                 }
783             }
784         } finally {
785             finishWrap(ctx, out, promise, inUnwrap, needUnwrap);
786         }
787     }
788 
789     private void finishWrap(ChannelHandlerContext ctx, ByteBuf out, ChannelPromise promise, boolean inUnwrap,
790             boolean needUnwrap) {
791         if (out == null) {
792             out = Unpooled.EMPTY_BUFFER;
793         } else if (!out.isReadable()) {
794             out.release();
795             out = Unpooled.EMPTY_BUFFER;
796         }
797 
798         if (promise != null) {
799             ctx.write(out, promise);
800         } else {
801             ctx.write(out);
802         }
803 
804         if (inUnwrap) {
805             needsFlush = true;
806         }
807 
808         if (needUnwrap) {
809             // The underlying engine is starving so we need to feed it with more data.
810             // See https://github.com/netty/netty/pull/5039
811             readIfNeeded(ctx);
812         }
813     }
814 
815     /**
816      * This method will not call
817      * {@link #setHandshakeFailure(ChannelHandlerContext, Throwable, boolean, boolean)} or
818      * {@link #setHandshakeFailure(ChannelHandlerContext, Throwable)}.
819      * @return {@code true} if this method ends on {@link SSLEngineResult.HandshakeStatus#NOT_HANDSHAKING}.
820      */
821     private boolean wrapNonAppData(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLException {
822         ByteBuf out = null;
823         ByteBufAllocator alloc = ctx.alloc();
824         try {
825             // Only continue to loop if the handler was not removed in the meantime.
826             // See https://github.com/netty/netty/issues/5860
827             while (!ctx.isRemoved()) {
828                 if (out == null) {
829                     // As this is called for the handshake we have no real idea how big the buffer needs to be.
830                     // That said 2048 should give us enough room to include everything like ALPN / NPN data.
831                     // If this is not enough we will increase the buffer in wrap(...).
832                     out = allocateOutNetBuf(ctx, 2048, 1);
833                 }
834                 SSLEngineResult result = wrap(alloc, engine, Unpooled.EMPTY_BUFFER, out);
835 
836                 if (result.bytesProduced() > 0) {
837                     ctx.write(out);
838                     if (inUnwrap) {
839                         needsFlush = true;
840                     }
841                     out = null;
842                 }
843 
844                 switch (result.getHandshakeStatus()) {
845                     case FINISHED:
846                         setHandshakeSuccess();
847                         return false;
848                     case NEED_TASK:
849                         runDelegatedTasks();
850                         break;
851                     case NEED_UNWRAP:
852                         if (inUnwrap) {
853                             // If we asked for a wrap, the engine requested an unwrap, and we are in unwrap there is
854                             // no use in trying to call wrap again because we have already attempted (or will after we
855                             // return) to feed more data to the engine.
856                             return false;
857                         }
858 
859                         unwrapNonAppData(ctx);
860                         break;
861                     case NEED_WRAP:
862                         break;
863                     case NOT_HANDSHAKING:
864                         setHandshakeSuccessIfStillHandshaking();
865                         // Workaround for TLS False Start problem reported at:
866                         // https://github.com/netty/netty/issues/1108#issuecomment-14266970
867                         if (!inUnwrap) {
868                             unwrapNonAppData(ctx);
869                         }
870                         return true;
871                     default:
872                         throw new IllegalStateException("Unknown handshake status: " + result.getHandshakeStatus());
873                 }
874 
875                 if (result.bytesProduced() == 0) {
876                     break;
877                 }
878 
879                 // It should not consume empty buffers when it is not handshaking
880                 // Fix for Android, where it was encrypting empty buffers even when not handshaking
881                 if (result.bytesConsumed() == 0 && result.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) {
882                     break;
883                 }
884             }
885         }  finally {
886             if (out != null) {
887                 out.release();
888             }
889         }
890         return false;
891     }
892 
893     private SSLEngineResult wrap(ByteBufAllocator alloc, SSLEngine engine, ByteBuf in, ByteBuf out)
894             throws SSLException {
895         ByteBuf newDirectIn = null;
896         try {
897             int readerIndex = in.readerIndex();
898             int readableBytes = in.readableBytes();
899 
900             // We will call SslEngine.wrap(ByteBuffer[], ByteBuffer) to allow efficient handling of
901             // CompositeByteBuf without force an extra memory copy when CompositeByteBuffer.nioBuffer() is called.
902             final ByteBuffer[] in0;
903             if (in.isDirect() || !engineType.wantsDirectBuffer) {
904                 // As CompositeByteBuf.nioBufferCount() can be expensive (as it needs to check all composed ByteBuf
905                 // to calculate the count) we will just assume a CompositeByteBuf contains more then 1 ByteBuf.
906                 // The worst that can happen is that we allocate an extra ByteBuffer[] in CompositeByteBuf.nioBuffers()
907                 // which is better then walking the composed ByteBuf in most cases.
908                 if (!(in instanceof CompositeByteBuf) && in.nioBufferCount() == 1) {
909                     in0 = singleBuffer;
910                     // We know its only backed by 1 ByteBuffer so use internalNioBuffer to keep object allocation
911                     // to a minimum.
912                     in0[0] = in.internalNioBuffer(readerIndex, readableBytes);
913                 } else {
914                     in0 = in.nioBuffers();
915                 }
916             } else {
917                 // We could even go further here and check if its a CompositeByteBuf and if so try to decompose it and
918                 // only replace the ByteBuffer that are not direct. At the moment we just will replace the whole
919                 // CompositeByteBuf to keep the complexity to a minimum
920                 newDirectIn = alloc.directBuffer(readableBytes);
921                 newDirectIn.writeBytes(in, readerIndex, readableBytes);
922                 in0 = singleBuffer;
923                 in0[0] = newDirectIn.internalNioBuffer(newDirectIn.readerIndex(), readableBytes);
924             }
925 
926             for (;;) {
927                 ByteBuffer out0 = out.nioBuffer(out.writerIndex(), out.writableBytes());
928                 SSLEngineResult result = engine.wrap(in0, out0);
929                 in.skipBytes(result.bytesConsumed());
930                 out.writerIndex(out.writerIndex() + result.bytesProduced());
931 
932                 switch (result.getStatus()) {
933                 case BUFFER_OVERFLOW:
934                     out.ensureWritable(engine.getSession().getPacketBufferSize());
935                     break;
936                 default:
937                     return result;
938                 }
939             }
940         } finally {
941             // Null out to allow GC of ByteBuffer
942             singleBuffer[0] = null;
943 
944             if (newDirectIn != null) {
945                 newDirectIn.release();
946             }
947         }
948     }
949 
950     @Override
951     public void channelInactive(ChannelHandlerContext ctx) throws Exception {
952         // Make sure to release SSLEngine,
953         // and notify the handshake future if the connection has been closed during handshake.
954         setHandshakeFailure(ctx, CHANNEL_CLOSED, !outboundClosed, handshakeStarted);
955 
956         // Ensure we always notify the sslClosePromise as well
957         notifyClosePromise(CHANNEL_CLOSED);
958 
959         super.channelInactive(ctx);
960     }
961 
962     @Override
963     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
964         if (ignoreException(cause)) {
965             // It is safe to ignore the 'connection reset by peer' or
966             // 'broken pipe' error after sending close_notify.
967             if (logger.isDebugEnabled()) {
968                 logger.debug(
969                         "{} Swallowing a harmless 'connection reset by peer / broken pipe' error that occurred " +
970                         "while writing close_notify in response to the peer's close_notify", ctx.channel(), cause);
971             }
972 
973             // Close the connection explicitly just in case the transport
974             // did not close the connection automatically.
975             if (ctx.channel().isActive()) {
976                 ctx.close();
977             }
978         } else {
979             ctx.fireExceptionCaught(cause);
980         }
981     }
982 
983     /**
984      * Checks if the given {@link Throwable} can be ignore and just "swallowed"
985      *
986      * When an ssl connection is closed a close_notify message is sent.
987      * After that the peer also sends close_notify however, it's not mandatory to receive
988      * the close_notify. The party who sent the initial close_notify can close the connection immediately
989      * then the peer will get connection reset error.
990      *
991      */
992     private boolean ignoreException(Throwable t) {
993         if (!(t instanceof SSLException) && t instanceof IOException && sslClosePromise.isDone()) {
994             String message = t.getMessage();
995 
996             // first try to match connection reset / broke peer based on the regex. This is the fastest way
997             // but may fail on different jdk impls or OS's
998             if (message != null && IGNORABLE_ERROR_MESSAGE.matcher(message).matches()) {
999                 return true;
1000             }
1001 
1002             // Inspect the StackTraceElements to see if it was a connection reset / broken pipe or not
1003             StackTraceElement[] elements = t.getStackTrace();
1004             for (StackTraceElement element: elements) {
1005                 String classname = element.getClassName();
1006                 String methodname = element.getMethodName();
1007 
1008                 // skip all classes that belong to the io.netty package
1009                 if (classname.startsWith("io.netty.")) {
1010                     continue;
1011                 }
1012 
1013                 // check if the method name is read if not skip it
1014                 if (!"read".equals(methodname)) {
1015                     continue;
1016                 }
1017 
1018                 // This will also match against SocketInputStream which is used by openjdk 7 and maybe
1019                 // also others
1020                 if (IGNORABLE_CLASS_IN_STACK.matcher(classname).matches()) {
1021                     return true;
1022                 }
1023 
1024                 try {
1025                     // No match by now.. Try to load the class via classloader and inspect it.
1026                     // This is mainly done as other JDK implementations may differ in name of
1027                     // the impl.
1028                     Class<?> clazz = PlatformDependent.getClassLoader(getClass()).loadClass(classname);
1029 
1030                     if (SocketChannel.class.isAssignableFrom(clazz)
1031                             || DatagramChannel.class.isAssignableFrom(clazz)) {
1032                         return true;
1033                     }
1034 
1035                     // also match against SctpChannel via String matching as it may not present.
1036                     if (PlatformDependent.javaVersion() >= 7
1037                             && "com.sun.nio.sctp.SctpChannel".equals(clazz.getSuperclass().getName())) {
1038                         return true;
1039                     }
1040                 } catch (Throwable cause) {
1041                     logger.debug("Unexpected exception while loading class {} classname {}",
1042                                  getClass(), classname, cause);
1043                 }
1044             }
1045         }
1046 
1047         return false;
1048     }
1049 
1050     /**
1051      * Returns {@code true} if the given {@link ByteBuf} is encrypted. Be aware that this method
1052      * will not increase the readerIndex of the given {@link ByteBuf}.
1053      *
1054      * @param   buffer
1055      *                  The {@link ByteBuf} to read from. Be aware that it must have at least 5 bytes to read,
1056      *                  otherwise it will throw an {@link IllegalArgumentException}.
1057      * @return encrypted
1058      *                  {@code true} if the {@link ByteBuf} is encrypted, {@code false} otherwise.
1059      * @throws IllegalArgumentException
1060      *                  Is thrown if the given {@link ByteBuf} has not at least 5 bytes to read.
1061      */
1062     public static boolean isEncrypted(ByteBuf buffer) {
1063         if (buffer.readableBytes() < SslUtils.SSL_RECORD_HEADER_LENGTH) {
1064             throw new IllegalArgumentException(
1065                     "buffer must have at least " + SslUtils.SSL_RECORD_HEADER_LENGTH + " readable bytes");
1066         }
1067         return getEncryptedPacketLength(buffer, buffer.readerIndex()) != SslUtils.NOT_ENCRYPTED;
1068     }
1069 
1070     private void decodeJdkCompatible(ChannelHandlerContext ctx, ByteBuf in) throws NotSslRecordException {
1071         int packetLength = this.packetLength;
1072         // If we calculated the length of the current SSL record before, use that information.
1073         if (packetLength > 0) {
1074             if (in.readableBytes() < packetLength) {
1075                 return;
1076             }
1077         } else {
1078             // Get the packet length and wait until we get a packets worth of data to unwrap.
1079             final int readableBytes = in.readableBytes();
1080             if (readableBytes < SslUtils.SSL_RECORD_HEADER_LENGTH) {
1081                 return;
1082             }
1083             packetLength = getEncryptedPacketLength(in, in.readerIndex());
1084             if (packetLength == SslUtils.NOT_ENCRYPTED) {
1085                 // Not an SSL/TLS packet
1086                 NotSslRecordException e = new NotSslRecordException(
1087                         "not an SSL/TLS record: " + ByteBufUtil.hexDump(in));
1088                 in.skipBytes(in.readableBytes());
1089 
1090                 // First fail the handshake promise as we may need to have access to the SSLEngine which may
1091                 // be released because the user will remove the SslHandler in an exceptionCaught(...) implementation.
1092                 setHandshakeFailure(ctx, e);
1093 
1094                 throw e;
1095             }
1096             assert packetLength > 0;
1097             if (packetLength > readableBytes) {
1098                 // wait until the whole packet can be read
1099                 this.packetLength = packetLength;
1100                 return;
1101             }
1102         }
1103 
1104         // Reset the state of this class so we can get the length of the next packet. We assume the entire packet will
1105         // be consumed by the SSLEngine.
1106         this.packetLength = 0;
1107         try {
1108             int bytesConsumed = unwrap(ctx, in, in.readerIndex(), packetLength);
1109             assert bytesConsumed == packetLength || engine.isInboundDone() :
1110                     "we feed the SSLEngine a packets worth of data: " + packetLength + " but it only consumed: " +
1111                             bytesConsumed;
1112             in.skipBytes(bytesConsumed);
1113         } catch (Throwable cause) {
1114             handleUnwrapThrowable(ctx, cause);
1115         }
1116     }
1117 
1118     private void decodeNonJdkCompatible(ChannelHandlerContext ctx, ByteBuf in) {
1119         try {
1120             in.skipBytes(unwrap(ctx, in, in.readerIndex(), in.readableBytes()));
1121         } catch (Throwable cause) {
1122             handleUnwrapThrowable(ctx, cause);
1123         }
1124     }
1125 
1126     private void handleUnwrapThrowable(ChannelHandlerContext ctx, Throwable cause) {
1127         try {
1128             // We should attempt to notify the handshake failure before writing any pending data. If we are in unwrap
1129             // and failed during the handshake process, and we attempt to wrap, then promises will fail, and if
1130             // listeners immediately close the Channel then we may end up firing the handshake event after the Channel
1131             // has been closed.
1132             if (handshakePromise.tryFailure(cause)) {
1133                 ctx.fireUserEventTriggered(new SslHandshakeCompletionEvent(cause));
1134             }
1135 
1136             // We need to flush one time as there may be an alert that we should send to the remote peer because
1137             // of the SSLException reported here.
1138             wrapAndFlush(ctx);
1139         } catch (SSLException ex) {
1140             logger.debug("SSLException during trying to call SSLEngine.wrap(...)" +
1141                     " because of an previous SSLException, ignoring...", ex);
1142         } finally {
1143             setHandshakeFailure(ctx, cause, true, false);
1144         }
1145         PlatformDependent.throwException(cause);
1146     }
1147 
1148     @Override
1149     protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws SSLException {
1150         if (jdkCompatibilityMode) {
1151             decodeJdkCompatible(ctx, in);
1152         } else {
1153             decodeNonJdkCompatible(ctx, in);
1154         }
1155     }
1156 
1157     @Override
1158     public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
1159         // Discard bytes of the cumulation buffer if needed.
1160         discardSomeReadBytes();
1161 
1162         flushIfNeeded(ctx);
1163         readIfNeeded(ctx);
1164 
1165         firedChannelRead = false;
1166         ctx.fireChannelReadComplete();
1167     }
1168 
1169     private void readIfNeeded(ChannelHandlerContext ctx) {
1170         // If handshake is not finished yet, we need more data.
1171         if (!ctx.channel().config().isAutoRead() && (!firedChannelRead || !handshakePromise.isDone())) {
1172             // No auto-read used and no message passed through the ChannelPipeline or the handshake was not complete
1173             // yet, which means we need to trigger the read to ensure we not encounter any stalls.
1174             ctx.read();
1175         }
1176     }
1177 
1178     private void flushIfNeeded(ChannelHandlerContext ctx) {
1179         if (needsFlush) {
1180             forceFlush(ctx);
1181         }
1182     }
1183 
1184     /**
1185      * Calls {@link SSLEngine#unwrap(ByteBuffer, ByteBuffer)} with an empty buffer to handle handshakes, etc.
1186      */
1187     private void unwrapNonAppData(ChannelHandlerContext ctx) throws SSLException {
1188         unwrap(ctx, Unpooled.EMPTY_BUFFER, 0, 0);
1189     }
1190 
1191     /**
1192      * Unwraps inbound SSL records.
1193      */
1194     private int unwrap(
1195             ChannelHandlerContext ctx, ByteBuf packet, int offset, int length) throws SSLException {
1196         final int originalLength = length;
1197         boolean wrapLater = false;
1198         boolean notifyClosure = false;
1199         int overflowReadableBytes = -1;
1200         ByteBuf decodeOut = allocate(ctx, length);
1201         try {
1202             // Only continue to loop if the handler was not removed in the meantime.
1203             // See https://github.com/netty/netty/issues/5860
1204             unwrapLoop: while (!ctx.isRemoved()) {
1205                 final SSLEngineResult result = engineType.unwrap(this, packet, offset, length, decodeOut);
1206                 final Status status = result.getStatus();
1207                 final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
1208                 final int produced = result.bytesProduced();
1209                 final int consumed = result.bytesConsumed();
1210 
1211                 // Update indexes for the next iteration
1212                 offset += consumed;
1213                 length -= consumed;
1214 
1215                 switch (status) {
1216                 case BUFFER_OVERFLOW:
1217                     final int readableBytes = decodeOut.readableBytes();
1218                     final int previousOverflowReadableBytes = overflowReadableBytes;
1219                     overflowReadableBytes = readableBytes;
1220                     int bufferSize = engine.getSession().getApplicationBufferSize() - readableBytes;
1221                     if (readableBytes > 0) {
1222                         firedChannelRead = true;
1223                         ctx.fireChannelRead(decodeOut);
1224 
1225                         // This buffer was handled, null it out.
1226                         decodeOut = null;
1227                         if (bufferSize <= 0) {
1228                             // It may happen that readableBytes >= engine.getSession().getApplicationBufferSize()
1229                             // while there is still more to unwrap, in this case we will just allocate a new buffer
1230                             // with the capacity of engine.getSession().getApplicationBufferSize() and call unwrap
1231                             // again.
1232                             bufferSize = engine.getSession().getApplicationBufferSize();
1233                         }
1234                     } else {
1235                         // This buffer was handled, null it out.
1236                         decodeOut.release();
1237                         decodeOut = null;
1238                     }
1239                     if (readableBytes == 0 && previousOverflowReadableBytes == 0) {
1240                         // If there is two consecutive loops where we overflow and are not able to consume any data,
1241                         // assume the amount of data exceeds the maximum amount for the engine and bail
1242                         throw new IllegalStateException("Two consecutive overflows but no content was consumed. " +
1243                                  SSLSession.class.getSimpleName() + " getApplicationBufferSize: " +
1244                                  engine.getSession().getApplicationBufferSize() + " maybe too small.");
1245                     }
1246                     // Allocate a new buffer which can hold all the rest data and loop again.
1247                     // TODO: We may want to reconsider how we calculate the length here as we may
1248                     // have more then one ssl message to decode.
1249                     decodeOut = allocate(ctx, engineType.calculatePendingData(this, bufferSize));
1250                     continue;
1251                 case CLOSED:
1252                     // notify about the CLOSED state of the SSLEngine. See #137
1253                     notifyClosure = true;
1254                     overflowReadableBytes = -1;
1255                     break;
1256                 default:
1257                     overflowReadableBytes = -1;
1258                     break;
1259                 }
1260 
1261                 switch (handshakeStatus) {
1262                     case NEED_UNWRAP:
1263                         break;
1264                     case NEED_WRAP:
1265                         // If the wrap operation transitions the status to NOT_HANDSHAKING and there is no more data to
1266                         // unwrap then the next call to unwrap will not produce any data. We can avoid the potentially
1267                         // costly unwrap operation and break out of the loop.
1268                         if (wrapNonAppData(ctx, true) && length == 0) {
1269                             break unwrapLoop;
1270                         }
1271                         break;
1272                     case NEED_TASK:
1273                         runDelegatedTasks();
1274                         break;
1275                     case FINISHED:
1276                         setHandshakeSuccess();
1277                         wrapLater = true;
1278 
1279                         // We 'break' here and NOT 'continue' as android API version 21 has a bug where they consume
1280                         // data from the buffer but NOT correctly set the SSLEngineResult.bytesConsumed().
1281                         // Because of this it will raise an exception on the next iteration of the for loop on android
1282                         // API version 21. Just doing a break will work here as produced and consumed will both be 0
1283                         // and so we break out of the complete for (;;) loop and so call decode(...) again later on.
1284                         // On other platforms this will have no negative effect as we will just continue with the
1285                         // for (;;) loop if something was either consumed or produced.
1286                         //
1287                         // See:
1288                         //  - https://github.com/netty/netty/issues/4116
1289                         //  - https://code.google.com/p/android/issues/detail?id=198639&thanks=198639&ts=1452501203
1290                         break;
1291                     case NOT_HANDSHAKING:
1292                         if (setHandshakeSuccessIfStillHandshaking()) {
1293                             wrapLater = true;
1294                             continue;
1295                         }
1296                         if (flushedBeforeHandshake) {
1297                             // We need to call wrap(...) in case there was a flush done before the handshake completed.
1298                             //
1299                             // See https://github.com/netty/netty/pull/2437
1300                             flushedBeforeHandshake = false;
1301                             wrapLater = true;
1302                         }
1303                         // If we are not handshaking and there is no more data to unwrap then the next call to unwrap
1304                         // will not produce any data. We can avoid the potentially costly unwrap operation and break
1305                         // out of the loop.
1306                         if (length == 0) {
1307                             break unwrapLoop;
1308                         }
1309                         break;
1310                     default:
1311                         throw new IllegalStateException("unknown handshake status: " + handshakeStatus);
1312                 }
1313 
1314                 if (status == Status.BUFFER_UNDERFLOW || consumed == 0 && produced == 0) {
1315                     if (handshakeStatus == HandshakeStatus.NEED_UNWRAP) {
1316                         // The underlying engine is starving so we need to feed it with more data.
1317                         // See https://github.com/netty/netty/pull/5039
1318                         readIfNeeded(ctx);
1319                     }
1320 
1321                     break;
1322                 }
1323             }
1324 
1325             if (wrapLater) {
1326                 wrap(ctx, true);
1327             }
1328 
1329             if (notifyClosure) {
1330                 notifyClosePromise(null);
1331             }
1332         } finally {
1333             if (decodeOut != null) {
1334                 if (decodeOut.isReadable()) {
1335                     firedChannelRead = true;
1336 
1337                     ctx.fireChannelRead(decodeOut);
1338                 } else {
1339                     decodeOut.release();
1340                 }
1341             }
1342         }
1343         return originalLength - length;
1344     }
1345 
1346     private static ByteBuffer toByteBuffer(ByteBuf out, int index, int len) {
1347         return out.nioBufferCount() == 1 ? out.internalNioBuffer(index, len) :
1348                 out.nioBuffer(index, len);
1349     }
1350 
1351     /**
1352      * Fetches all delegated tasks from the {@link SSLEngine} and runs them via the {@link #delegatedTaskExecutor}.
1353      * If the {@link #delegatedTaskExecutor} is {@link ImmediateExecutor}, just call {@link Runnable#run()} directly
1354      * instead of using {@link Executor#execute(Runnable)}.  Otherwise, run the tasks via
1355      * the {@link #delegatedTaskExecutor} and wait until the tasks are finished.
1356      */
1357     private void runDelegatedTasks() {
1358         if (delegatedTaskExecutor == ImmediateExecutor.INSTANCE) {
1359             for (;;) {
1360                 Runnable task = engine.getDelegatedTask();
1361                 if (task == null) {
1362                     break;
1363                 }
1364 
1365                 task.run();
1366             }
1367         } else {
1368             final List<Runnable> tasks = new ArrayList<Runnable>(2);
1369             for (;;) {
1370                 final Runnable task = engine.getDelegatedTask();
1371                 if (task == null) {
1372                     break;
1373                 }
1374 
1375                 tasks.add(task);
1376             }
1377 
1378             if (tasks.isEmpty()) {
1379                 return;
1380             }
1381 
1382             final CountDownLatch latch = new CountDownLatch(1);
1383             delegatedTaskExecutor.execute(new Runnable() {
1384                 @Override
1385                 public void run() {
1386                     try {
1387                         for (Runnable task: tasks) {
1388                             task.run();
1389                         }
1390                     } catch (Exception e) {
1391                         ctx.fireExceptionCaught(e);
1392                     } finally {
1393                         latch.countDown();
1394                     }
1395                 }
1396             });
1397 
1398             boolean interrupted = false;
1399             while (latch.getCount() != 0) {
1400                 try {
1401                     latch.await();
1402                 } catch (InterruptedException e) {
1403                     // Interrupt later.
1404                     interrupted = true;
1405                 }
1406             }
1407 
1408             if (interrupted) {
1409                 Thread.currentThread().interrupt();
1410             }
1411         }
1412     }
1413 
1414     /**
1415      * Works around some Android {@link SSLEngine} implementations that skip {@link HandshakeStatus#FINISHED} and
1416      * go straight into {@link HandshakeStatus#NOT_HANDSHAKING} when handshake is finished.
1417      *
1418      * @return {@code true} if and only if the workaround has been applied and thus {@link #handshakeFuture} has been
1419      *         marked as success by this method
1420      */
1421     private boolean setHandshakeSuccessIfStillHandshaking() {
1422         if (!handshakePromise.isDone()) {
1423             setHandshakeSuccess();
1424             return true;
1425         }
1426         return false;
1427     }
1428 
1429     /**
1430      * Notify all the handshake futures about the successfully handshake
1431      */
1432     private void setHandshakeSuccess() {
1433         handshakePromise.trySuccess(ctx.channel());
1434 
1435         if (logger.isDebugEnabled()) {
1436             logger.debug("{} HANDSHAKEN: {}", ctx.channel(), engine.getSession().getCipherSuite());
1437         }
1438         ctx.fireUserEventTriggered(SslHandshakeCompletionEvent.SUCCESS);
1439 
1440         if (readDuringHandshake && !ctx.channel().config().isAutoRead()) {
1441             readDuringHandshake = false;
1442             ctx.read();
1443         }
1444     }
1445 
1446     /**
1447      * Notify all the handshake futures about the failure during the handshake.
1448      */
1449     private void setHandshakeFailure(ChannelHandlerContext ctx, Throwable cause) {
1450         setHandshakeFailure(ctx, cause, true, true);
1451     }
1452 
1453     /**
1454      * Notify all the handshake futures about the failure during the handshake.
1455      */
1456     private void setHandshakeFailure(ChannelHandlerContext ctx, Throwable cause, boolean closeInbound, boolean notify) {
1457         try {
1458             // Release all resources such as internal buffers that SSLEngine
1459             // is managing.
1460             engine.closeOutbound();
1461 
1462             if (closeInbound) {
1463                 try {
1464                     engine.closeInbound();
1465                 } catch (SSLException e) {
1466                     if (logger.isDebugEnabled()) {
1467                         // only log in debug mode as it most likely harmless and latest chrome still trigger
1468                         // this all the time.
1469                         //
1470                         // See https://github.com/netty/netty/issues/1340
1471                         String msg = e.getMessage();
1472                         if (msg == null || !msg.contains("possible truncation attack")) {
1473                             logger.debug("{} SSLEngine.closeInbound() raised an exception.", ctx.channel(), e);
1474                         }
1475                     }
1476                 }
1477             }
1478             notifyHandshakeFailure(cause, notify);
1479         } finally {
1480             if (pendingUnencryptedWrites != null) {
1481                 // Ensure we remove and fail all pending writes in all cases and so release memory quickly.
1482                 pendingUnencryptedWrites.removeAndFailAll(cause);
1483             }
1484         }
1485     }
1486 
1487     private void notifyHandshakeFailure(Throwable cause, boolean notify) {
1488         if (handshakePromise.tryFailure(cause)) {
1489             SslUtils.notifyHandshakeFailure(ctx, cause, notify);
1490         }
1491     }
1492 
1493     private void notifyClosePromise(Throwable cause) {
1494         if (cause == null) {
1495             if (sslClosePromise.trySuccess(ctx.channel())) {
1496                 ctx.fireUserEventTriggered(SslCloseCompletionEvent.SUCCESS);
1497             }
1498         } else {
1499             if (sslClosePromise.tryFailure(cause)) {
1500                 ctx.fireUserEventTriggered(new SslCloseCompletionEvent(cause));
1501             }
1502         }
1503     }
1504 
1505     private void closeOutboundAndChannel(
1506             final ChannelHandlerContext ctx, final ChannelPromise promise, boolean disconnect) throws Exception {
1507         if (!ctx.channel().isActive()) {
1508             if (disconnect) {
1509                 ctx.disconnect(promise);
1510             } else {
1511                 ctx.close(promise);
1512             }
1513             return;
1514         }
1515 
1516         outboundClosed = true;
1517         engine.closeOutbound();
1518 
1519         ChannelPromise closeNotifyPromise = ctx.newPromise();
1520         try {
1521             flush(ctx, closeNotifyPromise);
1522         } finally {
1523             // It's important that we do not pass the original ChannelPromise to safeClose(...) as when flush(....)
1524             // throws an Exception it will be propagated to the AbstractChannelHandlerContext which will try
1525             // to fail the promise because of this. This will then fail as it was already completed by safeClose(...).
1526             // We create a new ChannelPromise and try to notify the original ChannelPromise
1527             // once it is complete. If we fail to do so we just ignore it as in this case it was failed already
1528             // because of a propagated Exception.
1529             //
1530             // See https://github.com/netty/netty/issues/5931
1531             safeClose(ctx, closeNotifyPromise, ctx.newPromise().addListener(
1532                     new ChannelPromiseNotifier(false, promise)));
1533         }
1534     }
1535 
1536     private void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
1537         if (pendingUnencryptedWrites != null) {
1538             pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, promise);
1539         } else {
1540             promise.setFailure(newPendingWritesNullException());
1541         }
1542         flush(ctx);
1543     }
1544 
1545     @Override
1546     public void handlerAdded(final ChannelHandlerContext ctx) throws Exception {
1547         this.ctx = ctx;
1548         pendingUnencryptedWrites = new PendingWriteQueue(ctx);
1549 
1550         if (ctx.channel().isActive()) {
1551             startHandshakeProcessing();
1552         }
1553     }
1554 
1555     private void startHandshakeProcessing() {
1556         handshakeStarted = true;
1557         if (engine.getUseClientMode()) {
1558             // Begin the initial handshake.
1559             // channelActive() event has been fired already, which means this.channelActive() will
1560             // not be invoked. We have to initialize here instead.
1561             handshake(null);
1562         } else {
1563             applyHandshakeTimeout(null);
1564         }
1565     }
1566 
1567     /**
1568      * Performs TLS renegotiation.
1569      */
1570     public Future<Channel> renegotiate() {
1571         ChannelHandlerContext ctx = this.ctx;
1572         if (ctx == null) {
1573             throw new IllegalStateException();
1574         }
1575 
1576         return renegotiate(ctx.executor().<Channel>newPromise());
1577     }
1578 
1579     /**
1580      * Performs TLS renegotiation.
1581      */
1582     public Future<Channel> renegotiate(final Promise<Channel> promise) {
1583         if (promise == null) {
1584             throw new NullPointerException("promise");
1585         }
1586 
1587         ChannelHandlerContext ctx = this.ctx;
1588         if (ctx == null) {
1589             throw new IllegalStateException();
1590         }
1591 
1592         EventExecutor executor = ctx.executor();
1593         if (!executor.inEventLoop()) {
1594             executor.execute(new Runnable() {
1595                 @Override
1596                 public void run() {
1597                     handshake(promise);
1598                 }
1599             });
1600             return promise;
1601         }
1602 
1603         handshake(promise);
1604         return promise;
1605     }
1606 
1607     /**
1608      * Performs TLS (re)negotiation.
1609      *
1610      * @param newHandshakePromise if {@code null}, use the existing {@link #handshakePromise},
1611      *                            assuming that the current negotiation has not been finished.
1612      *                            Currently, {@code null} is expected only for the initial handshake.
1613      */
1614     private void handshake(final Promise<Channel> newHandshakePromise) {
1615         final Promise<Channel> p;
1616         if (newHandshakePromise != null) {
1617             final Promise<Channel> oldHandshakePromise = handshakePromise;
1618             if (!oldHandshakePromise.isDone()) {
1619                 // There's no need to handshake because handshake is in progress already.
1620                 // Merge the new promise into the old one.
1621                 oldHandshakePromise.addListener(new FutureListener<Channel>() {
1622                     @Override
1623                     public void operationComplete(Future<Channel> future) throws Exception {
1624                         if (future.isSuccess()) {
1625                             newHandshakePromise.setSuccess(future.getNow());
1626                         } else {
1627                             newHandshakePromise.setFailure(future.cause());
1628                         }
1629                     }
1630                 });
1631                 return;
1632             }
1633 
1634             handshakePromise = p = newHandshakePromise;
1635         } else if (engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) {
1636             // Not all SSLEngine implementations support calling beginHandshake multiple times while a handshake
1637             // is in progress. See https://github.com/netty/netty/issues/4718.
1638             return;
1639         } else {
1640             // Forced to reuse the old handshake.
1641             p = handshakePromise;
1642             assert !p.isDone();
1643         }
1644 
1645         // Begin handshake.
1646         final ChannelHandlerContext ctx = this.ctx;
1647         try {
1648             engine.beginHandshake();
1649             wrapNonAppData(ctx, false);
1650         } catch (Throwable e) {
1651             setHandshakeFailure(ctx, e);
1652         } finally {
1653            forceFlush(ctx);
1654         }
1655         applyHandshakeTimeout(p);
1656     }
1657 
1658     private void applyHandshakeTimeout(Promise<Channel> p) {
1659         final Promise<Channel> promise = p == null ? handshakePromise : p;
1660         // Set timeout if necessary.
1661         final long handshakeTimeoutMillis = this.handshakeTimeoutMillis;
1662         if (handshakeTimeoutMillis <= 0 || promise.isDone()) {
1663             return;
1664         }
1665 
1666         final ScheduledFuture<?> timeoutFuture = ctx.executor().schedule(new Runnable() {
1667             @Override
1668             public void run() {
1669                 if (promise.isDone()) {
1670                     return;
1671                 }
1672                 notifyHandshakeFailure(HANDSHAKE_TIMED_OUT, true);
1673             }
1674         }, handshakeTimeoutMillis, TimeUnit.MILLISECONDS);
1675 
1676         // Cancel the handshake timeout when handshake is finished.
1677         promise.addListener(new FutureListener<Channel>() {
1678             @Override
1679             public void operationComplete(Future<Channel> f) throws Exception {
1680                 timeoutFuture.cancel(false);
1681             }
1682         });
1683     }
1684 
1685     private void forceFlush(ChannelHandlerContext ctx) {
1686         needsFlush = false;
1687         ctx.flush();
1688     }
1689 
1690     /**
1691      * Issues an initial TLS handshake once connected when used in client-mode
1692      */
1693     @Override
1694     public void channelActive(final ChannelHandlerContext ctx) throws Exception {
1695         if (!startTls) {
1696             startHandshakeProcessing();
1697         }
1698         ctx.fireChannelActive();
1699     }
1700 
1701     private void safeClose(
1702             final ChannelHandlerContext ctx, final ChannelFuture flushFuture,
1703             final ChannelPromise promise) {
1704         if (!ctx.channel().isActive()) {
1705             ctx.close(promise);
1706             return;
1707         }
1708 
1709         final ScheduledFuture<?> timeoutFuture;
1710         if (!flushFuture.isDone()) {
1711             long closeNotifyTimeout = closeNotifyFlushTimeoutMillis;
1712             if (closeNotifyTimeout > 0) {
1713                 // Force-close the connection if close_notify is not fully sent in time.
1714                 timeoutFuture = ctx.executor().schedule(new Runnable() {
1715                     @Override
1716                     public void run() {
1717                         // May be done in the meantime as cancel(...) is only best effort.
1718                         if (!flushFuture.isDone()) {
1719                             logger.warn("{} Last write attempt timed out; force-closing the connection.",
1720                                     ctx.channel());
1721                             addCloseListener(ctx.close(ctx.newPromise()), promise);
1722                         }
1723                     }
1724                 }, closeNotifyTimeout, TimeUnit.MILLISECONDS);
1725             } else {
1726                 timeoutFuture = null;
1727             }
1728         } else {
1729             timeoutFuture = null;
1730         }
1731 
1732         // Close the connection if close_notify is sent in time.
1733         flushFuture.addListener(new ChannelFutureListener() {
1734             @Override
1735             public void operationComplete(ChannelFuture f)
1736                     throws Exception {
1737                 if (timeoutFuture != null) {
1738                     timeoutFuture.cancel(false);
1739                 }
1740                 final long closeNotifyReadTimeout = closeNotifyReadTimeoutMillis;
1741                 if (closeNotifyReadTimeout <= 0) {
1742                     // Trigger the close in all cases to make sure the promise is notified
1743                     // See https://github.com/netty/netty/issues/2358
1744                     addCloseListener(ctx.close(ctx.newPromise()), promise);
1745                 } else {
1746                     final ScheduledFuture<?> closeNotifyReadTimeoutFuture;
1747 
1748                     if (!sslClosePromise.isDone()) {
1749                         closeNotifyReadTimeoutFuture = ctx.executor().schedule(new Runnable() {
1750                             @Override
1751                             public void run() {
1752                                 if (!sslClosePromise.isDone()) {
1753                                     logger.debug(
1754                                             "{} did not receive close_notify in {}ms; force-closing the connection.",
1755                                             ctx.channel(), closeNotifyReadTimeout);
1756 
1757                                     // Do the close now...
1758                                     addCloseListener(ctx.close(ctx.newPromise()), promise);
1759                                 }
1760                             }
1761                         }, closeNotifyReadTimeout, TimeUnit.MILLISECONDS);
1762                     } else {
1763                         closeNotifyReadTimeoutFuture = null;
1764                     }
1765 
1766                     // Do the close once the we received the close_notify.
1767                     sslClosePromise.addListener(new FutureListener<Channel>() {
1768                         @Override
1769                         public void operationComplete(Future<Channel> future) throws Exception {
1770                             if (closeNotifyReadTimeoutFuture != null) {
1771                                 closeNotifyReadTimeoutFuture.cancel(false);
1772                             }
1773                             addCloseListener(ctx.close(ctx.newPromise()), promise);
1774                         }
1775                     });
1776                 }
1777             }
1778         });
1779     }
1780 
1781     private static void addCloseListener(ChannelFuture future, ChannelPromise promise) {
1782         // We notify the promise in the ChannelPromiseNotifier as there is a "race" where the close(...) call
1783         // by the timeoutFuture and the close call in the flushFuture listener will be called. Because of
1784         // this we need to use trySuccess() and tryFailure(...) as otherwise we can cause an
1785         // IllegalStateException.
1786         // Also we not want to log if the notification happens as this is expected in some cases.
1787         // See https://github.com/netty/netty/issues/5598
1788         future.addListener(new ChannelPromiseNotifier(false, promise));
1789     }
1790 
1791     /**
1792      * Always prefer a direct buffer when it's pooled, so that we reduce the number of memory copies
1793      * in {@link OpenSslEngine}.
1794      */
1795     private ByteBuf allocate(ChannelHandlerContext ctx, int capacity) {
1796         ByteBufAllocator alloc = ctx.alloc();
1797         if (engineType.wantsDirectBuffer) {
1798             return alloc.directBuffer(capacity);
1799         } else {
1800             return alloc.buffer(capacity);
1801         }
1802     }
1803 
1804     /**
1805      * Allocates an outbound network buffer for {@link SSLEngine#wrap(ByteBuffer, ByteBuffer)} which can encrypt
1806      * the specified amount of pending bytes.
1807      */
1808     private ByteBuf allocateOutNetBuf(ChannelHandlerContext ctx, int pendingBytes, int numComponents) {
1809         return allocate(ctx, engineType.calculateWrapBufferCapacity(this, pendingBytes, numComponents));
1810     }
1811 
1812     private final class LazyChannelPromise extends DefaultPromise<Channel> {
1813 
1814         @Override
1815         protected EventExecutor executor() {
1816             if (ctx == null) {
1817                 throw new IllegalStateException();
1818             }
1819             return ctx.executor();
1820         }
1821 
1822         @Override
1823         protected void checkDeadLock() {
1824             if (ctx == null) {
1825                 // If ctx is null the handlerAdded(...) callback was not called, in this case the checkDeadLock()
1826                 // method was called from another Thread then the one that is used by ctx.executor(). We need to
1827                 // guard against this as a user can see a race if handshakeFuture().sync() is called but the
1828                 // handlerAdded(..) method was not yet as it is called from the EventExecutor of the
1829                 // ChannelHandlerContext. If we not guard against this super.checkDeadLock() would cause an
1830                 // IllegalStateException when trying to call executor().
1831                 return;
1832             }
1833             super.checkDeadLock();
1834         }
1835     }
1836 }