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.AbstractCoalescingBufferQueue;
24 import io.netty.channel.Channel;
25 import io.netty.channel.ChannelConfig;
26 import io.netty.channel.ChannelException;
27 import io.netty.channel.ChannelFuture;
28 import io.netty.channel.ChannelFutureListener;
29 import io.netty.channel.ChannelHandlerContext;
30 import io.netty.channel.ChannelInboundHandler;
31 import io.netty.channel.ChannelOutboundHandler;
32 import io.netty.channel.ChannelPipeline;
33 import io.netty.channel.ChannelPromise;
34 import io.netty.channel.ChannelPromiseNotifier;
35 import io.netty.handler.codec.ByteToMessageDecoder;
36 import io.netty.handler.codec.DecoderException;
37 import io.netty.handler.codec.UnsupportedMessageTypeException;
38 import io.netty.util.ReferenceCountUtil;
39 import io.netty.util.ReferenceCounted;
40 import io.netty.util.concurrent.DefaultPromise;
41 import io.netty.util.concurrent.EventExecutor;
42 import io.netty.util.concurrent.Future;
43 import io.netty.util.concurrent.FutureListener;
44 import io.netty.util.concurrent.ImmediateExecutor;
45 import io.netty.util.concurrent.Promise;
46 import io.netty.util.concurrent.PromiseNotifier;
47 import io.netty.util.internal.ObjectUtil;
48 import io.netty.util.internal.PlatformDependent;
49 import io.netty.util.internal.UnstableApi;
50 import io.netty.util.internal.logging.InternalLogger;
51 import io.netty.util.internal.logging.InternalLoggerFactory;
52
53 import java.io.IOException;
54 import java.net.SocketAddress;
55 import java.nio.ByteBuffer;
56 import java.nio.channels.ClosedChannelException;
57 import java.nio.channels.DatagramChannel;
58 import java.nio.channels.SocketChannel;
59 import java.util.List;
60 import java.util.concurrent.Executor;
61 import java.util.concurrent.RejectedExecutionException;
62 import java.util.concurrent.ScheduledFuture;
63 import java.util.concurrent.TimeUnit;
64 import java.util.regex.Pattern;
65
66 import javax.net.ssl.SSLEngine;
67 import javax.net.ssl.SSLEngineResult;
68 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
69 import javax.net.ssl.SSLEngineResult.Status;
70 import javax.net.ssl.SSLException;
71 import javax.net.ssl.SSLHandshakeException;
72 import javax.net.ssl.SSLSession;
73
74 import static io.netty.buffer.ByteBufUtil.ensureWritableSuccess;
75 import static io.netty.handler.ssl.SslUtils.getEncryptedPacketLength;
76
77 /**
78 * Adds <a href="http://en.wikipedia.org/wiki/Transport_Layer_Security">SSL
79 * · TLS</a> and StartTLS support to a {@link Channel}. Please refer
80 * to the <strong>"SecureChat"</strong> example in the distribution or the web
81 * site for the detailed usage.
82 *
83 * <h3>Beginning the handshake</h3>
84 * <p>
85 * Beside using the handshake {@link ChannelFuture} to get notified about the completion of the handshake it's
86 * also possible to detect it by implement the
87 * {@link ChannelInboundHandler#userEventTriggered(ChannelHandlerContext, Object)}
88 * method and check for a {@link SslHandshakeCompletionEvent}.
89 *
90 * <h3>Handshake</h3>
91 * <p>
92 * The handshake will be automatically issued for you once the {@link Channel} is active and
93 * {@link SSLEngine#getUseClientMode()} returns {@code true}.
94 * So no need to bother with it by your self.
95 *
96 * <h3>Closing the session</h3>
97 * <p>
98 * To close the SSL session, the {@link #closeOutbound()} method should be
99 * called to send the {@code close_notify} message to the remote peer. One
100 * exception is when you close the {@link Channel} - {@link SslHandler}
101 * intercepts the close request and send the {@code close_notify} message
102 * before the channel closure automatically. Once the SSL session is closed,
103 * it is not reusable, and consequently you should create a new
104 * {@link SslHandler} with a new {@link SSLEngine} as explained in the
105 * following section.
106 *
107 * <h3>Restarting the session</h3>
108 * <p>
109 * To restart the SSL session, you must remove the existing closed
110 * {@link SslHandler} from the {@link ChannelPipeline}, insert a new
111 * {@link SslHandler} with a new {@link SSLEngine} into the pipeline,
112 * and start the handshake process as described in the first section.
113 *
114 * <h3>Implementing StartTLS</h3>
115 * <p>
116 * <a href="http://en.wikipedia.org/wiki/STARTTLS">StartTLS</a> is the
117 * communication pattern that secures the wire in the middle of the plaintext
118 * connection. Please note that it is different from SSL · TLS, that
119 * secures the wire from the beginning of the connection. Typically, StartTLS
120 * is composed of three steps:
121 * <ol>
122 * <li>Client sends a StartTLS request to server.</li>
123 * <li>Server sends a StartTLS response to client.</li>
124 * <li>Client begins SSL handshake.</li>
125 * </ol>
126 * If you implement a server, you need to:
127 * <ol>
128 * <li>create a new {@link SslHandler} instance with {@code startTls} flag set
129 * to {@code true},</li>
130 * <li>insert the {@link SslHandler} to the {@link ChannelPipeline}, and</li>
131 * <li>write a StartTLS response.</li>
132 * </ol>
133 * Please note that you must insert {@link SslHandler} <em>before</em> sending
134 * the StartTLS response. Otherwise the client can send begin SSL handshake
135 * before {@link SslHandler} is inserted to the {@link ChannelPipeline}, causing
136 * data corruption.
137 * <p>
138 * The client-side implementation is much simpler.
139 * <ol>
140 * <li>Write a StartTLS request,</li>
141 * <li>wait for the StartTLS response,</li>
142 * <li>create a new {@link SslHandler} instance with {@code startTls} flag set
143 * to {@code false},</li>
144 * <li>insert the {@link SslHandler} to the {@link ChannelPipeline}, and</li>
145 * <li>Initiate SSL handshake.</li>
146 * </ol>
147 *
148 * <h3>Known issues</h3>
149 * <p>
150 * Because of a known issue with the current implementation of the SslEngine that comes
151 * with Java it may be possible that you see blocked IO-Threads while a full GC is done.
152 * <p>
153 * So if you are affected you can workaround this problem by adjust the cache settings
154 * like shown below:
155 *
156 * <pre>
157 * SslContext context = ...;
158 * context.getServerSessionContext().setSessionCacheSize(someSaneSize);
159 * context.getServerSessionContext().setSessionTime(someSameTimeout);
160 * </pre>
161 * <p>
162 * What values to use here depends on the nature of your application and should be set
163 * based on monitoring and debugging of it.
164 * For more details see
165 * <a href="https://github.com/netty/netty/issues/832">#832</a> in our issue tracker.
166 */
167 public class SslHandler extends ByteToMessageDecoder implements ChannelOutboundHandler {
168
169 private static final InternalLogger logger =
170 InternalLoggerFactory.getInstance(SslHandler.class);
171
172 private static final Pattern IGNORABLE_CLASS_IN_STACK = Pattern.compile(
173 "^.*(?:Socket|Datagram|Sctp|Udt)Channel.*$");
174 private static final Pattern IGNORABLE_ERROR_MESSAGE = Pattern.compile(
175 "^.*(?:connection.*(?:reset|closed|abort|broken)|broken.*pipe).*$", Pattern.CASE_INSENSITIVE);
176
177 /**
178 * <a href="https://tools.ietf.org/html/rfc5246#section-6.2">2^14</a> which is the maximum sized plaintext chunk
179 * allowed by the TLS RFC.
180 */
181 private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024;
182
183 private enum SslEngineType {
184 TCNATIVE(true, COMPOSITE_CUMULATOR) {
185 @Override
186 SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
187 throws SSLException {
188 int nioBufferCount = in.nioBufferCount();
189 int writerIndex = out.writerIndex();
190 final SSLEngineResult result;
191 if (nioBufferCount > 1) {
192 /*
193 * If {@link OpenSslEngine} is in use,
194 * we can use a special {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} method
195 * that accepts multiple {@link ByteBuffer}s without additional memory copies.
196 */
197 ReferenceCountedOpenSslEngine opensslEngine = (ReferenceCountedOpenSslEngine) handler.engine;
198 try {
199 handler.singleBuffer[0] = toByteBuffer(out, writerIndex,
200 out.writableBytes());
201 result = opensslEngine.unwrap(in.nioBuffers(readerIndex, len), handler.singleBuffer);
202 } finally {
203 handler.singleBuffer[0] = null;
204 }
205 } else {
206 result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
207 toByteBuffer(out, writerIndex, out.writableBytes()));
208 }
209 out.writerIndex(writerIndex + result.bytesProduced());
210 return result;
211 }
212
213 @Override
214 ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
215 int pendingBytes, int numComponents) {
216 return allocator.directBuffer(((ReferenceCountedOpenSslEngine) handler.engine)
217 .calculateMaxLengthForWrap(pendingBytes, numComponents));
218 }
219
220 @Override
221 int calculatePendingData(SslHandler handler, int guess) {
222 int sslPending = ((ReferenceCountedOpenSslEngine) handler.engine).sslPending();
223 return sslPending > 0 ? sslPending : guess;
224 }
225
226 @Override
227 boolean jdkCompatibilityMode(SSLEngine engine) {
228 return ((ReferenceCountedOpenSslEngine) engine).jdkCompatibilityMode;
229 }
230 },
231 CONSCRYPT(true, COMPOSITE_CUMULATOR) {
232 @Override
233 SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
234 throws SSLException {
235 int nioBufferCount = in.nioBufferCount();
236 int writerIndex = out.writerIndex();
237 final SSLEngineResult result;
238 if (nioBufferCount > 1) {
239 /*
240 * Use a special unwrap method without additional memory copies.
241 */
242 try {
243 handler.singleBuffer[0] = toByteBuffer(out, writerIndex, out.writableBytes());
244 result = ((ConscryptAlpnSslEngine) handler.engine).unwrap(
245 in.nioBuffers(readerIndex, len),
246 handler.singleBuffer);
247 } finally {
248 handler.singleBuffer[0] = null;
249 }
250 } else {
251 result = handler.engine.unwrap(toByteBuffer(in, readerIndex, len),
252 toByteBuffer(out, writerIndex, out.writableBytes()));
253 }
254 out.writerIndex(writerIndex + result.bytesProduced());
255 return result;
256 }
257
258 @Override
259 ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
260 int pendingBytes, int numComponents) {
261 return allocator.directBuffer(
262 ((ConscryptAlpnSslEngine) handler.engine).calculateOutNetBufSize(pendingBytes, numComponents));
263 }
264
265 @Override
266 int calculatePendingData(SslHandler handler, int guess) {
267 return guess;
268 }
269
270 @Override
271 boolean jdkCompatibilityMode(SSLEngine engine) {
272 return true;
273 }
274 },
275 JDK(false, MERGE_CUMULATOR) {
276 @Override
277 SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
278 throws SSLException {
279 int writerIndex = out.writerIndex();
280 ByteBuffer inNioBuffer = toByteBuffer(in, readerIndex, len);
281 int position = inNioBuffer.position();
282 final SSLEngineResult result = handler.engine.unwrap(inNioBuffer,
283 toByteBuffer(out, writerIndex, out.writableBytes()));
284 out.writerIndex(writerIndex + result.bytesProduced());
285
286 // This is a workaround for a bug in Android 5.0. Android 5.0 does not correctly update the
287 // SSLEngineResult.bytesConsumed() in some cases and just return 0.
288 //
289 // See:
290 // - https://android-review.googlesource.com/c/platform/external/conscrypt/+/122080
291 // - https://github.com/netty/netty/issues/7758
292 if (result.bytesConsumed() == 0) {
293 int consumed = inNioBuffer.position() - position;
294 if (consumed != result.bytesConsumed()) {
295 // Create a new SSLEngineResult with the correct bytesConsumed().
296 return new SSLEngineResult(
297 result.getStatus(), result.getHandshakeStatus(), consumed, result.bytesProduced());
298 }
299 }
300 return result;
301 }
302
303 @Override
304 ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
305 int pendingBytes, int numComponents) {
306 // As for the JDK SSLEngine we always need to allocate buffers of the size required by the SSLEngine
307 // (normally ~16KB). This is required even if the amount of data to encrypt is very small. Use heap
308 // buffers to reduce the native memory usage.
309 //
310 // Beside this the JDK SSLEngine also (as of today) will do an extra heap to direct buffer copy
311 // if a direct buffer is used as its internals operate on byte[].
312 return allocator.heapBuffer(handler.engine.getSession().getPacketBufferSize());
313 }
314
315 @Override
316 int calculatePendingData(SslHandler handler, int guess) {
317 return guess;
318 }
319
320 @Override
321 boolean jdkCompatibilityMode(SSLEngine engine) {
322 return true;
323 }
324 };
325
326 static SslEngineType forEngine(SSLEngine engine) {
327 return engine instanceof ReferenceCountedOpenSslEngine ? TCNATIVE :
328 engine instanceof ConscryptAlpnSslEngine ? CONSCRYPT : JDK;
329 }
330
331 SslEngineType(boolean wantsDirectBuffer, Cumulator cumulator) {
332 this.wantsDirectBuffer = wantsDirectBuffer;
333 this.cumulator = cumulator;
334 }
335
336 abstract SSLEngineResult unwrap(SslHandler handler, ByteBuf in, int readerIndex, int len, ByteBuf out)
337 throws SSLException;
338
339 abstract int calculatePendingData(SslHandler handler, int guess);
340
341 abstract boolean jdkCompatibilityMode(SSLEngine engine);
342
343 abstract ByteBuf allocateWrapBuffer(SslHandler handler, ByteBufAllocator allocator,
344 int pendingBytes, int numComponents);
345
346 // BEGIN Platform-dependent flags
347
348 /**
349 * {@code true} if and only if {@link SSLEngine} expects a direct buffer and so if a heap buffer
350 * is given will make an extra memory copy.
351 */
352 final boolean wantsDirectBuffer;
353
354 // END Platform-dependent flags
355
356 /**
357 * When using JDK {@link SSLEngine}, we use {@link #MERGE_CUMULATOR} because it works only with
358 * one {@link ByteBuffer}.
359 *
360 * When using {@link OpenSslEngine}, we can use {@link #COMPOSITE_CUMULATOR} because it has
361 * {@link OpenSslEngine#unwrap(ByteBuffer[], ByteBuffer[])} which works with multiple {@link ByteBuffer}s
362 * and which does not need to do extra memory copies.
363 */
364 final Cumulator cumulator;
365 }
366
367 private volatile ChannelHandlerContext ctx;
368 private final SSLEngine engine;
369 private final SslEngineType engineType;
370 private final Executor delegatedTaskExecutor;
371 private final boolean jdkCompatibilityMode;
372
373 /**
374 * Used if {@link SSLEngine#wrap(ByteBuffer[], ByteBuffer)} and {@link SSLEngine#unwrap(ByteBuffer, ByteBuffer[])}
375 * should be called with a {@link ByteBuf} that is only backed by one {@link ByteBuffer} to reduce the object
376 * creation.
377 */
378 private final ByteBuffer[] singleBuffer = new ByteBuffer[1];
379
380 private final boolean startTls;
381 private boolean sentFirstMessage;
382 private boolean flushedBeforeHandshake;
383 private boolean readDuringHandshake;
384 private boolean handshakeStarted;
385
386 private SslHandlerCoalescingBufferQueue pendingUnencryptedWrites;
387 private Promise<Channel> handshakePromise = new LazyChannelPromise();
388 private final LazyChannelPromise sslClosePromise = new LazyChannelPromise();
389
390 /**
391 * Set by wrap*() methods when something is produced.
392 * {@link #channelReadComplete(ChannelHandlerContext)} will check this flag, clear it, and call ctx.flush().
393 */
394 private boolean needsFlush;
395
396 private boolean outboundClosed;
397 private boolean closeNotify;
398 private boolean processTask;
399
400 private int packetLength;
401
402 /**
403 * This flag is used to determine if we need to call {@link ChannelHandlerContext#read()} to consume more data
404 * when {@link ChannelConfig#isAutoRead()} is {@code false}.
405 */
406 private boolean firedChannelRead;
407
408 private volatile long handshakeTimeoutMillis = 10000;
409 private volatile long closeNotifyFlushTimeoutMillis = 3000;
410 private volatile long closeNotifyReadTimeoutMillis;
411 volatile int wrapDataSize = MAX_PLAINTEXT_LENGTH;
412
413 /**
414 * Creates a new instance which runs all delegated tasks directly on the {@link EventExecutor}.
415 *
416 * @param engine the {@link SSLEngine} this handler will use
417 */
418 public SslHandler(SSLEngine engine) {
419 this(engine, false);
420 }
421
422 /**
423 * Creates a new instance which runs all delegated tasks directly on the {@link EventExecutor}.
424 *
425 * @param engine the {@link SSLEngine} this handler will use
426 * @param startTls {@code true} if the first write request shouldn't be
427 * encrypted by the {@link SSLEngine}
428 */
429 public SslHandler(SSLEngine engine, boolean startTls) {
430 this(engine, startTls, ImmediateExecutor.INSTANCE);
431 }
432
433 /**
434 * Creates a new instance.
435 *
436 * @param engine the {@link SSLEngine} this handler will use
437 * @param delegatedTaskExecutor the {@link Executor} that will be used to execute tasks that are returned by
438 * {@link SSLEngine#getDelegatedTask()}.
439 */
440 public SslHandler(SSLEngine engine, Executor delegatedTaskExecutor) {
441 this(engine, false, delegatedTaskExecutor);
442 }
443
444 /**
445 * Creates a new instance.
446 *
447 * @param engine the {@link SSLEngine} this handler will use
448 * @param startTls {@code true} if the first write request shouldn't be
449 * encrypted by the {@link SSLEngine}
450 * @param delegatedTaskExecutor the {@link Executor} that will be used to execute tasks that are returned by
451 * {@link SSLEngine#getDelegatedTask()}.
452 */
453 public SslHandler(SSLEngine engine, boolean startTls, Executor delegatedTaskExecutor) {
454 this.engine = ObjectUtil.checkNotNull(engine, "engine");
455 this.delegatedTaskExecutor = ObjectUtil.checkNotNull(delegatedTaskExecutor, "delegatedTaskExecutor");
456 engineType = SslEngineType.forEngine(engine);
457 this.startTls = startTls;
458 this.jdkCompatibilityMode = engineType.jdkCompatibilityMode(engine);
459 setCumulator(engineType.cumulator);
460 }
461
462 public long getHandshakeTimeoutMillis() {
463 return handshakeTimeoutMillis;
464 }
465
466 public void setHandshakeTimeout(long handshakeTimeout, TimeUnit unit) {
467 ObjectUtil.checkNotNull(unit, "unit");
468 setHandshakeTimeoutMillis(unit.toMillis(handshakeTimeout));
469 }
470
471 public void setHandshakeTimeoutMillis(long handshakeTimeoutMillis) {
472 if (handshakeTimeoutMillis < 0) {
473 throw new IllegalArgumentException(
474 "handshakeTimeoutMillis: " + handshakeTimeoutMillis + " (expected: >= 0)");
475 }
476 this.handshakeTimeoutMillis = handshakeTimeoutMillis;
477 }
478
479 /**
480 * Sets the number of bytes to pass to each {@link SSLEngine#wrap(ByteBuffer[], int, int, ByteBuffer)} call.
481 * <p>
482 * This value will partition data which is passed to write
483 * {@link #write(ChannelHandlerContext, Object, ChannelPromise)}. The partitioning will work as follows:
484 * <ul>
485 * <li>If {@code wrapDataSize <= 0} then we will write each data chunk as is.</li>
486 * <li>If {@code wrapDataSize > data size} then we will attempt to aggregate multiple data chunks together.</li>
487 * <li>If {@code wrapDataSize > data size} Else if {@code wrapDataSize <= data size} then we will divide the data
488 * into chunks of {@code wrapDataSize} when writing.</li>
489 * </ul>
490 * <p>
491 * If the {@link SSLEngine} doesn't support a gather wrap operation (e.g. {@link SslProvider#OPENSSL}) then
492 * aggregating data before wrapping can help reduce the ratio between TLS overhead vs data payload which will lead
493 * to better goodput. Writing fixed chunks of data can also help target the underlying transport's (e.g. TCP)
494 * frame size. Under lossy/congested network conditions this may help the peer get full TLS packets earlier and
495 * be able to do work sooner, as opposed to waiting for the all the pieces of the TLS packet to arrive.
496 * @param wrapDataSize the number of bytes which will be passed to each
497 * {@link SSLEngine#wrap(ByteBuffer[], int, int, ByteBuffer)} call.
498 */
499 @UnstableApi
500 public final void setWrapDataSize(int wrapDataSize) {
501 this.wrapDataSize = wrapDataSize;
502 }
503
504 /**
505 * @deprecated use {@link #getCloseNotifyFlushTimeoutMillis()}
506 */
507 @Deprecated
508 public long getCloseNotifyTimeoutMillis() {
509 return getCloseNotifyFlushTimeoutMillis();
510 }
511
512 /**
513 * @deprecated use {@link #setCloseNotifyFlushTimeout(long, TimeUnit)}
514 */
515 @Deprecated
516 public void setCloseNotifyTimeout(long closeNotifyTimeout, TimeUnit unit) {
517 setCloseNotifyFlushTimeout(closeNotifyTimeout, unit);
518 }
519
520 /**
521 * @deprecated use {@link #setCloseNotifyFlushTimeoutMillis(long)}
522 */
523 @Deprecated
524 public void setCloseNotifyTimeoutMillis(long closeNotifyFlushTimeoutMillis) {
525 setCloseNotifyFlushTimeoutMillis(closeNotifyFlushTimeoutMillis);
526 }
527
528 /**
529 * Gets the timeout for flushing the close_notify that was triggered by closing the
530 * {@link Channel}. If the close_notify was not flushed in the given timeout the {@link Channel} will be closed
531 * forcibly.
532 */
533 public final long getCloseNotifyFlushTimeoutMillis() {
534 return closeNotifyFlushTimeoutMillis;
535 }
536
537 /**
538 * Sets the timeout for flushing the close_notify that was triggered by closing the
539 * {@link Channel}. If the close_notify was not flushed in the given timeout the {@link Channel} will be closed
540 * forcibly.
541 */
542 public final void setCloseNotifyFlushTimeout(long closeNotifyFlushTimeout, TimeUnit unit) {
543 setCloseNotifyFlushTimeoutMillis(unit.toMillis(closeNotifyFlushTimeout));
544 }
545
546 /**
547 * See {@link #setCloseNotifyFlushTimeout(long, TimeUnit)}.
548 */
549 public final void setCloseNotifyFlushTimeoutMillis(long closeNotifyFlushTimeoutMillis) {
550 if (closeNotifyFlushTimeoutMillis < 0) {
551 throw new IllegalArgumentException(
552 "closeNotifyFlushTimeoutMillis: " + closeNotifyFlushTimeoutMillis + " (expected: >= 0)");
553 }
554 this.closeNotifyFlushTimeoutMillis = closeNotifyFlushTimeoutMillis;
555 }
556
557 /**
558 * Gets the timeout (in ms) for receiving the response for the close_notify that was triggered by closing the
559 * {@link Channel}. This timeout starts after the close_notify message was successfully written to the
560 * remote peer. Use {@code 0} to directly close the {@link Channel} and not wait for the response.
561 */
562 public final long getCloseNotifyReadTimeoutMillis() {
563 return closeNotifyReadTimeoutMillis;
564 }
565
566 /**
567 * Sets the timeout for receiving the response for the close_notify that was triggered by closing the
568 * {@link Channel}. This timeout starts after the close_notify message was successfully written to the
569 * remote peer. Use {@code 0} to directly close the {@link Channel} and not wait for the response.
570 */
571 public final void setCloseNotifyReadTimeout(long closeNotifyReadTimeout, TimeUnit unit) {
572 setCloseNotifyReadTimeoutMillis(unit.toMillis(closeNotifyReadTimeout));
573 }
574
575 /**
576 * See {@link #setCloseNotifyReadTimeout(long, TimeUnit)}.
577 */
578 public final void setCloseNotifyReadTimeoutMillis(long closeNotifyReadTimeoutMillis) {
579 if (closeNotifyReadTimeoutMillis < 0) {
580 throw new IllegalArgumentException(
581 "closeNotifyReadTimeoutMillis: " + closeNotifyReadTimeoutMillis + " (expected: >= 0)");
582 }
583 this.closeNotifyReadTimeoutMillis = closeNotifyReadTimeoutMillis;
584 }
585
586 /**
587 * Returns the {@link SSLEngine} which is used by this handler.
588 */
589 public SSLEngine engine() {
590 return engine;
591 }
592
593 /**
594 * Returns the name of the current application-level protocol.
595 *
596 * @return the protocol name or {@code null} if application-level protocol has not been negotiated
597 */
598 public String applicationProtocol() {
599 SSLEngine engine = engine();
600 if (!(engine instanceof ApplicationProtocolAccessor)) {
601 return null;
602 }
603
604 return ((ApplicationProtocolAccessor) engine).getNegotiatedApplicationProtocol();
605 }
606
607 /**
608 * Returns a {@link Future} that will get notified once the current TLS handshake completes.
609 *
610 * @return the {@link Future} for the initial TLS handshake if {@link #renegotiate()} was not invoked.
611 * The {@link Future} for the most recent {@linkplain #renegotiate() TLS renegotiation} otherwise.
612 */
613 public Future<Channel> handshakeFuture() {
614 return handshakePromise;
615 }
616
617 /**
618 * Use {@link #closeOutbound()}
619 */
620 @Deprecated
621 public ChannelFuture close() {
622 return closeOutbound();
623 }
624
625 /**
626 * Use {@link #closeOutbound(ChannelPromise)}
627 */
628 @Deprecated
629 public ChannelFuture close(ChannelPromise promise) {
630 return closeOutbound(promise);
631 }
632
633 /**
634 * Sends an SSL {@code close_notify} message to the specified channel and
635 * destroys the underlying {@link SSLEngine}. This will <strong>not</strong> close the underlying
636 * {@link Channel}. If you want to also close the {@link Channel} use {@link Channel#close()} or
637 * {@link ChannelHandlerContext#close()}
638 */
639 public ChannelFuture closeOutbound() {
640 return closeOutbound(ctx.newPromise());
641 }
642
643 /**
644 * Sends an SSL {@code close_notify} message to the specified channel and
645 * destroys the underlying {@link SSLEngine}. This will <strong>not</strong> close the underlying
646 * {@link Channel}. If you want to also close the {@link Channel} use {@link Channel#close()} or
647 * {@link ChannelHandlerContext#close()}
648 */
649 public ChannelFuture closeOutbound(final ChannelPromise promise) {
650 final ChannelHandlerContext ctx = this.ctx;
651 if (ctx.executor().inEventLoop()) {
652 closeOutbound0(promise);
653 } else {
654 ctx.executor().execute(new Runnable() {
655 @Override
656 public void run() {
657 closeOutbound0(promise);
658 }
659 });
660 }
661 return promise;
662 }
663
664 private void closeOutbound0(ChannelPromise promise) {
665 outboundClosed = true;
666 engine.closeOutbound();
667 try {
668 flush(ctx, promise);
669 } catch (Exception e) {
670 if (!promise.tryFailure(e)) {
671 logger.warn("{} flush() raised a masked exception.", ctx.channel(), e);
672 }
673 }
674 }
675
676 /**
677 * Return the {@link Future} that will get notified if the inbound of the {@link SSLEngine} is closed.
678 *
679 * This method will return the same {@link Future} all the time.
680 *
681 * @see SSLEngine
682 */
683 public Future<Channel> sslCloseFuture() {
684 return sslClosePromise;
685 }
686
687 @Override
688 public void handlerRemoved0(ChannelHandlerContext ctx) throws Exception {
689 if (!pendingUnencryptedWrites.isEmpty()) {
690 // Check if queue is not empty first because create a new ChannelException is expensive
691 pendingUnencryptedWrites.releaseAndFailAll(ctx,
692 new ChannelException("Pending write on removal of SslHandler"));
693 }
694 pendingUnencryptedWrites = null;
695
696 SSLHandshakeException cause = null;
697
698 // If the handshake is not done yet we should fail the handshake promise and notify the rest of the
699 // pipeline.
700 if (!handshakePromise.isDone()) {
701 cause = new SSLHandshakeException("SslHandler removed before handshake completed");
702 if (handshakePromise.tryFailure(cause)) {
703 ctx.fireUserEventTriggered(new SslHandshakeCompletionEvent(cause));
704 }
705 }
706 if (!sslClosePromise.isDone()) {
707 if (cause == null) {
708 cause = new SSLHandshakeException("SslHandler removed before handshake completed");
709 }
710 notifyClosePromise(cause);
711 }
712
713 if (engine instanceof ReferenceCounted) {
714 ((ReferenceCounted) engine).release();
715 }
716 }
717
718 @Override
719 public void bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
720 ctx.bind(localAddress, promise);
721 }
722
723 @Override
724 public void connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress,
725 ChannelPromise promise) throws Exception {
726 ctx.connect(remoteAddress, localAddress, promise);
727 }
728
729 @Override
730 public void deregister(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
731 ctx.deregister(promise);
732 }
733
734 @Override
735 public void disconnect(final ChannelHandlerContext ctx,
736 final ChannelPromise promise) throws Exception {
737 closeOutboundAndChannel(ctx, promise, true);
738 }
739
740 @Override
741 public void close(final ChannelHandlerContext ctx,
742 final ChannelPromise promise) throws Exception {
743 closeOutboundAndChannel(ctx, promise, false);
744 }
745
746 @Override
747 public void read(ChannelHandlerContext ctx) throws Exception {
748 if (!handshakePromise.isDone()) {
749 readDuringHandshake = true;
750 }
751
752 ctx.read();
753 }
754
755 private static IllegalStateException newPendingWritesNullException() {
756 return new IllegalStateException("pendingUnencryptedWrites is null, handlerRemoved0 called?");
757 }
758
759 @Override
760 public void write(final ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
761 if (!(msg instanceof ByteBuf)) {
762 UnsupportedMessageTypeException exception = new UnsupportedMessageTypeException(msg, ByteBuf.class);
763 ReferenceCountUtil.safeRelease(msg);
764 promise.setFailure(exception);
765 } else if (pendingUnencryptedWrites == null) {
766 ReferenceCountUtil.safeRelease(msg);
767 promise.setFailure(newPendingWritesNullException());
768 } else {
769 pendingUnencryptedWrites.add((ByteBuf) msg, promise);
770 }
771 }
772
773 @Override
774 public void flush(ChannelHandlerContext ctx) throws Exception {
775 // Do not encrypt the first write request if this handler is
776 // created with startTLS flag turned on.
777 if (startTls && !sentFirstMessage) {
778 sentFirstMessage = true;
779 pendingUnencryptedWrites.writeAndRemoveAll(ctx);
780 forceFlush(ctx);
781 // Explicit start handshake processing once we send the first message. This will also ensure
782 // we will schedule the timeout if needed.
783 startHandshakeProcessing();
784 return;
785 }
786
787 if (processTask) {
788 return;
789 }
790
791 try {
792 wrapAndFlush(ctx);
793 } catch (Throwable cause) {
794 setHandshakeFailure(ctx, cause);
795 PlatformDependent.throwException(cause);
796 }
797 }
798
799 private void wrapAndFlush(ChannelHandlerContext ctx) throws SSLException {
800 if (pendingUnencryptedWrites.isEmpty()) {
801 // It's important to NOT use a voidPromise here as the user
802 // may want to add a ChannelFutureListener to the ChannelPromise later.
803 //
804 // See https://github.com/netty/netty/issues/3364
805 pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, ctx.newPromise());
806 }
807 if (!handshakePromise.isDone()) {
808 flushedBeforeHandshake = true;
809 }
810 try {
811 wrap(ctx, false);
812 } finally {
813 // We may have written some parts of data before an exception was thrown so ensure we always flush.
814 // See https://github.com/netty/netty/issues/3900#issuecomment-172481830
815 forceFlush(ctx);
816 }
817 }
818
819 // This method will not call setHandshakeFailure(...) !
820 private void wrap(ChannelHandlerContext ctx, boolean inUnwrap) throws SSLException {
821 ByteBuf out = null;
822 ChannelPromise promise = null;
823 ByteBufAllocator alloc = ctx.alloc();
824 boolean needUnwrap = false;
825 ByteBuf buf = null;
826 try {
827 final int wrapDataSize = this.wrapDataSize;
828 // Only continue to loop if the handler was not removed in the meantime.
829 // See https://github.com/netty/netty/issues/5860
830 outer: while (!ctx.isRemoved()) {
831 promise = ctx.newPromise();
832 buf = wrapDataSize > 0 ?
833 pendingUnencryptedWrites.remove(alloc, wrapDataSize, promise) :
834 pendingUnencryptedWrites.removeFirst(promise);
835 if (buf == null) {
836 break;
837 }
838
839 if (out == null) {
840 out = allocateOutNetBuf(ctx, buf.readableBytes(), buf.nioBufferCount());
841 }
842
843 SSLEngineResult result = wrap(alloc, engine, buf, out);
844
845 if (result.getStatus() == Status.CLOSED) {
846 buf.release();
847 buf = null;
848 // Make a best effort to preserve any exception that way previously encountered from the handshake
849 // or the transport, else fallback to a general error.
850 Throwable exception = handshakePromise.cause();
851 if (exception == null) {
852 exception = sslClosePromise.cause();
853 if (exception == null) {
854 exception = new SSLException("SSLEngine closed already");
855 }
856 }
857 promise.tryFailure(exception);
858 promise = null;
859 // SSLEngine has been closed already.
860 // Any further write attempts should be denied.
861 pendingUnencryptedWrites.releaseAndFailAll(ctx, exception);
862 return;
863 } else {
864 if (buf.isReadable()) {
865 pendingUnencryptedWrites.addFirst(buf, promise);
866 // When we add the buffer/promise pair back we need to be sure we don't complete the promise
867 // later in finishWrap. We only complete the promise if the buffer is completely consumed.
868 promise = null;
869 } else {
870 buf.release();
871 }
872 buf = null;
873
874 switch (result.getHandshakeStatus()) {
875 case NEED_TASK:
876 if (!runDelegatedTasks(inUnwrap)) {
877 // We scheduled a task on the delegatingTaskExecutor, so stop processing as we will
878 // resume once the task completes.
879 break outer;
880 }
881 break;
882 case FINISHED:
883 setHandshakeSuccess();
884 // deliberate fall-through
885 case NOT_HANDSHAKING:
886 setHandshakeSuccessIfStillHandshaking();
887 // deliberate fall-through
888 case NEED_WRAP: {
889 ChannelPromise p = promise;
890
891 // Null out the promise so it is not reused in the finally block in the cause of
892 // finishWrap(...) throwing.
893 promise = null;
894 final ByteBuf b;
895
896 if (out.isReadable()) {
897 // There is something in the out buffer. Ensure we null it out so it is not re-used.
898 b = out;
899 out = null;
900 } else {
901 // If out is not readable we can re-use it and so save an extra allocation
902 b = null;
903 }
904 finishWrap(ctx, b, p, inUnwrap, false);
905 // If we are expected to wrap again and we produced some data we need to ensure there
906 // is something in the queue to process as otherwise we will not try again before there
907 // was more added. Failing to do so may fail to produce an alert that can be
908 // consumed by the remote peer.
909 if (result.bytesProduced() > 0 && pendingUnencryptedWrites.isEmpty()) {
910 pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER);
911 }
912 break;
913 }
914 case NEED_UNWRAP:
915 needUnwrap = true;
916 return;
917 default:
918 throw new IllegalStateException(
919 "Unknown handshake status: " + result.getHandshakeStatus());
920 }
921 }
922 }
923 } finally {
924 // Ownership of buffer was not transferred, release it.
925 if (buf != null) {
926 buf.release();
927 }
928 finishWrap(ctx, out, promise, inUnwrap, needUnwrap);
929 }
930 }
931
932 private void finishWrap(ChannelHandlerContext ctx, ByteBuf out, ChannelPromise promise, boolean inUnwrap,
933 boolean needUnwrap) {
934 if (out == null) {
935 out = Unpooled.EMPTY_BUFFER;
936 } else if (!out.isReadable()) {
937 out.release();
938 out = Unpooled.EMPTY_BUFFER;
939 }
940
941 if (promise != null) {
942 ctx.write(out, promise);
943 } else {
944 ctx.write(out);
945 }
946
947 if (inUnwrap) {
948 needsFlush = true;
949 }
950
951 if (needUnwrap) {
952 // The underlying engine is starving so we need to feed it with more data.
953 // See https://github.com/netty/netty/pull/5039
954 readIfNeeded(ctx);
955 }
956 }
957
958 /**
959 * This method will not call
960 * {@link #setHandshakeFailure(ChannelHandlerContext, Throwable, boolean, boolean, boolean)} or
961 * {@link #setHandshakeFailure(ChannelHandlerContext, Throwable)}.
962 * @return {@code true} if this method ends on {@link SSLEngineResult.HandshakeStatus#NOT_HANDSHAKING}.
963 */
964 private boolean wrapNonAppData(final ChannelHandlerContext ctx, boolean inUnwrap) throws SSLException {
965 ByteBuf out = null;
966 ByteBufAllocator alloc = ctx.alloc();
967 try {
968 // Only continue to loop if the handler was not removed in the meantime.
969 // See https://github.com/netty/netty/issues/5860
970 outer: while (!ctx.isRemoved()) {
971 if (out == null) {
972 // As this is called for the handshake we have no real idea how big the buffer needs to be.
973 // That said 2048 should give us enough room to include everything like ALPN / NPN data.
974 // If this is not enough we will increase the buffer in wrap(...).
975 out = allocateOutNetBuf(ctx, 2048, 1);
976 }
977 SSLEngineResult result = wrap(alloc, engine, Unpooled.EMPTY_BUFFER, out);
978
979 if (result.bytesProduced() > 0) {
980 ctx.write(out).addListener(new ChannelFutureListener() {
981 @Override
982 public void operationComplete(ChannelFuture future) {
983 Throwable cause = future.cause();
984 if (cause != null) {
985 setHandshakeFailureTransportFailure(ctx, cause);
986 }
987 }
988 });
989 if (inUnwrap) {
990 needsFlush = true;
991 }
992 out = null;
993 }
994
995 HandshakeStatus status = result.getHandshakeStatus();
996 switch (status) {
997 case FINISHED:
998 setHandshakeSuccess();
999 return false;
1000 case NEED_TASK:
1001 if (!runDelegatedTasks(inUnwrap)) {
1002 // We scheduled a task on the delegatingTaskExecutor, so stop processing as we will
1003 // resume once the task completes.
1004 break outer;
1005 }
1006 break;
1007 case NEED_UNWRAP:
1008 if (inUnwrap) {
1009 // If we asked for a wrap, the engine requested an unwrap, and we are in unwrap there is
1010 // no use in trying to call wrap again because we have already attempted (or will after we
1011 // return) to feed more data to the engine.
1012 return false;
1013 }
1014
1015 unwrapNonAppData(ctx);
1016 break;
1017 case NEED_WRAP:
1018 break;
1019 case NOT_HANDSHAKING:
1020 setHandshakeSuccessIfStillHandshaking();
1021 // Workaround for TLS False Start problem reported at:
1022 // https://github.com/netty/netty/issues/1108#issuecomment-14266970
1023 if (!inUnwrap) {
1024 unwrapNonAppData(ctx);
1025 }
1026 return true;
1027 default:
1028 throw new IllegalStateException("Unknown handshake status: " + result.getHandshakeStatus());
1029 }
1030
1031 // Check if did not produce any bytes and if so break out of the loop, but only if we did not process
1032 // a task as last action. It's fine to not produce any data as part of executing a task.
1033 if (result.bytesProduced() == 0 && status != HandshakeStatus.NEED_TASK) {
1034 break;
1035 }
1036
1037 // It should not consume empty buffers when it is not handshaking
1038 // Fix for Android, where it was encrypting empty buffers even when not handshaking
1039 if (result.bytesConsumed() == 0 && result.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING) {
1040 break;
1041 }
1042 }
1043 } finally {
1044 if (out != null) {
1045 out.release();
1046 }
1047 }
1048 return false;
1049 }
1050
1051 private SSLEngineResult wrap(ByteBufAllocator alloc, SSLEngine engine, ByteBuf in, ByteBuf out)
1052 throws SSLException {
1053 ByteBuf newDirectIn = null;
1054 try {
1055 int readerIndex = in.readerIndex();
1056 int readableBytes = in.readableBytes();
1057
1058 // We will call SslEngine.wrap(ByteBuffer[], ByteBuffer) to allow efficient handling of
1059 // CompositeByteBuf without force an extra memory copy when CompositeByteBuffer.nioBuffer() is called.
1060 final ByteBuffer[] in0;
1061 if (in.isDirect() || !engineType.wantsDirectBuffer) {
1062 // As CompositeByteBuf.nioBufferCount() can be expensive (as it needs to check all composed ByteBuf
1063 // to calculate the count) we will just assume a CompositeByteBuf contains more then 1 ByteBuf.
1064 // The worst that can happen is that we allocate an extra ByteBuffer[] in CompositeByteBuf.nioBuffers()
1065 // which is better then walking the composed ByteBuf in most cases.
1066 if (!(in instanceof CompositeByteBuf) && in.nioBufferCount() == 1) {
1067 in0 = singleBuffer;
1068 // We know its only backed by 1 ByteBuffer so use internalNioBuffer to keep object allocation
1069 // to a minimum.
1070 in0[0] = in.internalNioBuffer(readerIndex, readableBytes);
1071 } else {
1072 in0 = in.nioBuffers();
1073 }
1074 } else {
1075 // We could even go further here and check if its a CompositeByteBuf and if so try to decompose it and
1076 // only replace the ByteBuffer that are not direct. At the moment we just will replace the whole
1077 // CompositeByteBuf to keep the complexity to a minimum
1078 newDirectIn = alloc.directBuffer(readableBytes);
1079 newDirectIn.writeBytes(in, readerIndex, readableBytes);
1080 in0 = singleBuffer;
1081 in0[0] = newDirectIn.internalNioBuffer(newDirectIn.readerIndex(), readableBytes);
1082 }
1083
1084 for (;;) {
1085 ByteBuffer out0 = out.nioBuffer(out.writerIndex(), out.writableBytes());
1086 SSLEngineResult result = engine.wrap(in0, out0);
1087 in.skipBytes(result.bytesConsumed());
1088 out.writerIndex(out.writerIndex() + result.bytesProduced());
1089
1090 switch (result.getStatus()) {
1091 case BUFFER_OVERFLOW:
1092 out.ensureWritable(engine.getSession().getPacketBufferSize());
1093 break;
1094 default:
1095 return result;
1096 }
1097 }
1098 } finally {
1099 // Null out to allow GC of ByteBuffer
1100 singleBuffer[0] = null;
1101
1102 if (newDirectIn != null) {
1103 newDirectIn.release();
1104 }
1105 }
1106 }
1107
1108 @Override
1109 public void channelInactive(ChannelHandlerContext ctx) throws Exception {
1110 boolean handshakeFailed = handshakePromise.cause() != null;
1111
1112 ClosedChannelException exception = new ClosedChannelException();
1113 // Make sure to release SSLEngine,
1114 // and notify the handshake future if the connection has been closed during handshake.
1115 setHandshakeFailure(ctx, exception, !outboundClosed, handshakeStarted, false);
1116
1117 // Ensure we always notify the sslClosePromise as well
1118 notifyClosePromise(exception);
1119
1120 try {
1121 super.channelInactive(ctx);
1122 } catch (DecoderException e) {
1123 if (!handshakeFailed || !(e.getCause() instanceof SSLException)) {
1124 // We only rethrow the exception if the handshake did not fail before channelInactive(...) was called
1125 // as otherwise this may produce duplicated failures as super.channelInactive(...) will also call
1126 // channelRead(...).
1127 //
1128 // See https://github.com/netty/netty/issues/10119
1129 throw e;
1130 }
1131 }
1132 }
1133
1134 @Override
1135 public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
1136 if (ignoreException(cause)) {
1137 // It is safe to ignore the 'connection reset by peer' or
1138 // 'broken pipe' error after sending close_notify.
1139 if (logger.isDebugEnabled()) {
1140 logger.debug(
1141 "{} Swallowing a harmless 'connection reset by peer / broken pipe' error that occurred " +
1142 "while writing close_notify in response to the peer's close_notify", ctx.channel(), cause);
1143 }
1144
1145 // Close the connection explicitly just in case the transport
1146 // did not close the connection automatically.
1147 if (ctx.channel().isActive()) {
1148 ctx.close();
1149 }
1150 } else {
1151 ctx.fireExceptionCaught(cause);
1152 }
1153 }
1154
1155 /**
1156 * Checks if the given {@link Throwable} can be ignore and just "swallowed"
1157 *
1158 * When an ssl connection is closed a close_notify message is sent.
1159 * After that the peer also sends close_notify however, it's not mandatory to receive
1160 * the close_notify. The party who sent the initial close_notify can close the connection immediately
1161 * then the peer will get connection reset error.
1162 *
1163 */
1164 private boolean ignoreException(Throwable t) {
1165 if (!(t instanceof SSLException) && t instanceof IOException && sslClosePromise.isDone()) {
1166 String message = t.getMessage();
1167
1168 // first try to match connection reset / broke peer based on the regex. This is the fastest way
1169 // but may fail on different jdk impls or OS's
1170 if (message != null && IGNORABLE_ERROR_MESSAGE.matcher(message).matches()) {
1171 return true;
1172 }
1173
1174 // Inspect the StackTraceElements to see if it was a connection reset / broken pipe or not
1175 StackTraceElement[] elements = t.getStackTrace();
1176 for (StackTraceElement element: elements) {
1177 String classname = element.getClassName();
1178 String methodname = element.getMethodName();
1179
1180 // skip all classes that belong to the io.netty package
1181 if (classname.startsWith("io.netty.")) {
1182 continue;
1183 }
1184
1185 // check if the method name is read if not skip it
1186 if (!"read".equals(methodname)) {
1187 continue;
1188 }
1189
1190 // This will also match against SocketInputStream which is used by openjdk 7 and maybe
1191 // also others
1192 if (IGNORABLE_CLASS_IN_STACK.matcher(classname).matches()) {
1193 return true;
1194 }
1195
1196 try {
1197 // No match by now.. Try to load the class via classloader and inspect it.
1198 // This is mainly done as other JDK implementations may differ in name of
1199 // the impl.
1200 Class<?> clazz = PlatformDependent.getClassLoader(getClass()).loadClass(classname);
1201
1202 if (SocketChannel.class.isAssignableFrom(clazz)
1203 || DatagramChannel.class.isAssignableFrom(clazz)) {
1204 return true;
1205 }
1206
1207 // also match against SctpChannel via String matching as it may not present.
1208 if (PlatformDependent.javaVersion() >= 7
1209 && "com.sun.nio.sctp.SctpChannel".equals(clazz.getSuperclass().getName())) {
1210 return true;
1211 }
1212 } catch (Throwable cause) {
1213 if (logger.isDebugEnabled()) {
1214 logger.debug("Unexpected exception while loading class {} classname {}",
1215 getClass(), classname, cause);
1216 }
1217 }
1218 }
1219 }
1220
1221 return false;
1222 }
1223
1224 /**
1225 * Returns {@code true} if the given {@link ByteBuf} is encrypted. Be aware that this method
1226 * will not increase the readerIndex of the given {@link ByteBuf}.
1227 *
1228 * @param buffer
1229 * The {@link ByteBuf} to read from. Be aware that it must have at least 5 bytes to read,
1230 * otherwise it will throw an {@link IllegalArgumentException}.
1231 * @return encrypted
1232 * {@code true} if the {@link ByteBuf} is encrypted, {@code false} otherwise.
1233 * @throws IllegalArgumentException
1234 * Is thrown if the given {@link ByteBuf} has not at least 5 bytes to read.
1235 */
1236 public static boolean isEncrypted(ByteBuf buffer) {
1237 if (buffer.readableBytes() < SslUtils.SSL_RECORD_HEADER_LENGTH) {
1238 throw new IllegalArgumentException(
1239 "buffer must have at least " + SslUtils.SSL_RECORD_HEADER_LENGTH + " readable bytes");
1240 }
1241 return getEncryptedPacketLength(buffer, buffer.readerIndex()) != SslUtils.NOT_ENCRYPTED;
1242 }
1243
1244 private void decodeJdkCompatible(ChannelHandlerContext ctx, ByteBuf in) throws NotSslRecordException {
1245 int packetLength = this.packetLength;
1246 // If we calculated the length of the current SSL record before, use that information.
1247 if (packetLength > 0) {
1248 if (in.readableBytes() < packetLength) {
1249 return;
1250 }
1251 } else {
1252 // Get the packet length and wait until we get a packets worth of data to unwrap.
1253 final int readableBytes = in.readableBytes();
1254 if (readableBytes < SslUtils.SSL_RECORD_HEADER_LENGTH) {
1255 return;
1256 }
1257 packetLength = getEncryptedPacketLength(in, in.readerIndex());
1258 if (packetLength == SslUtils.NOT_ENCRYPTED) {
1259 // Not an SSL/TLS packet
1260 NotSslRecordException e = new NotSslRecordException(
1261 "not an SSL/TLS record: " + ByteBufUtil.hexDump(in));
1262 in.skipBytes(in.readableBytes());
1263
1264 // First fail the handshake promise as we may need to have access to the SSLEngine which may
1265 // be released because the user will remove the SslHandler in an exceptionCaught(...) implementation.
1266 setHandshakeFailure(ctx, e);
1267
1268 throw e;
1269 }
1270 assert packetLength > 0;
1271 if (packetLength > readableBytes) {
1272 // wait until the whole packet can be read
1273 this.packetLength = packetLength;
1274 return;
1275 }
1276 }
1277
1278 // Reset the state of this class so we can get the length of the next packet. We assume the entire packet will
1279 // be consumed by the SSLEngine.
1280 this.packetLength = 0;
1281 try {
1282 int bytesConsumed = unwrap(ctx, in, in.readerIndex(), packetLength);
1283 assert bytesConsumed == packetLength || engine.isInboundDone() :
1284 "we feed the SSLEngine a packets worth of data: " + packetLength + " but it only consumed: " +
1285 bytesConsumed;
1286 in.skipBytes(bytesConsumed);
1287 } catch (Throwable cause) {
1288 handleUnwrapThrowable(ctx, cause);
1289 }
1290 }
1291
1292 private void decodeNonJdkCompatible(ChannelHandlerContext ctx, ByteBuf in) {
1293 try {
1294 in.skipBytes(unwrap(ctx, in, in.readerIndex(), in.readableBytes()));
1295 } catch (Throwable cause) {
1296 handleUnwrapThrowable(ctx, cause);
1297 }
1298 }
1299
1300 private void handleUnwrapThrowable(ChannelHandlerContext ctx, Throwable cause) {
1301 try {
1302 // We should attempt to notify the handshake failure before writing any pending data. If we are in unwrap
1303 // and failed during the handshake process, and we attempt to wrap, then promises will fail, and if
1304 // listeners immediately close the Channel then we may end up firing the handshake event after the Channel
1305 // has been closed.
1306 if (handshakePromise.tryFailure(cause)) {
1307 ctx.fireUserEventTriggered(new SslHandshakeCompletionEvent(cause));
1308 }
1309
1310 // We need to flush one time as there may be an alert that we should send to the remote peer because
1311 // of the SSLException reported here.
1312 wrapAndFlush(ctx);
1313 } catch (SSLException ex) {
1314 logger.debug("SSLException during trying to call SSLEngine.wrap(...)" +
1315 " because of an previous SSLException, ignoring...", ex);
1316 } finally {
1317 // ensure we always flush and close the channel.
1318 setHandshakeFailure(ctx, cause, true, false, true);
1319 }
1320 PlatformDependent.throwException(cause);
1321 }
1322
1323 @Override
1324 protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws SSLException {
1325 if (processTask) {
1326 return;
1327 }
1328 if (jdkCompatibilityMode) {
1329 decodeJdkCompatible(ctx, in);
1330 } else {
1331 decodeNonJdkCompatible(ctx, in);
1332 }
1333 }
1334
1335 @Override
1336 public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
1337 channelReadComplete0(ctx);
1338 }
1339
1340 private void channelReadComplete0(ChannelHandlerContext ctx) {
1341 // Discard bytes of the cumulation buffer if needed.
1342 discardSomeReadBytes();
1343
1344 flushIfNeeded(ctx);
1345 readIfNeeded(ctx);
1346
1347 firedChannelRead = false;
1348 ctx.fireChannelReadComplete();
1349 }
1350
1351 private void readIfNeeded(ChannelHandlerContext ctx) {
1352 // If handshake is not finished yet, we need more data.
1353 if (!ctx.channel().config().isAutoRead() && (!firedChannelRead || !handshakePromise.isDone())) {
1354 // No auto-read used and no message passed through the ChannelPipeline or the handshake was not complete
1355 // yet, which means we need to trigger the read to ensure we not encounter any stalls.
1356 ctx.read();
1357 }
1358 }
1359
1360 private void flushIfNeeded(ChannelHandlerContext ctx) {
1361 if (needsFlush) {
1362 forceFlush(ctx);
1363 }
1364 }
1365
1366 /**
1367 * Calls {@link SSLEngine#unwrap(ByteBuffer, ByteBuffer)} with an empty buffer to handle handshakes, etc.
1368 */
1369 private void unwrapNonAppData(ChannelHandlerContext ctx) throws SSLException {
1370 unwrap(ctx, Unpooled.EMPTY_BUFFER, 0, 0);
1371 }
1372
1373 /**
1374 * Unwraps inbound SSL records.
1375 */
1376 private int unwrap(
1377 ChannelHandlerContext ctx, ByteBuf packet, int offset, int length) throws SSLException {
1378 final int originalLength = length;
1379 boolean wrapLater = false;
1380 boolean notifyClosure = false;
1381 int overflowReadableBytes = -1;
1382 ByteBuf decodeOut = allocate(ctx, length);
1383 try {
1384 // Only continue to loop if the handler was not removed in the meantime.
1385 // See https://github.com/netty/netty/issues/5860
1386 unwrapLoop: while (!ctx.isRemoved()) {
1387 final SSLEngineResult result = engineType.unwrap(this, packet, offset, length, decodeOut);
1388 final Status status = result.getStatus();
1389 final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
1390 final int produced = result.bytesProduced();
1391 final int consumed = result.bytesConsumed();
1392
1393 // Update indexes for the next iteration
1394 offset += consumed;
1395 length -= consumed;
1396
1397 switch (status) {
1398 case BUFFER_OVERFLOW:
1399 final int readableBytes = decodeOut.readableBytes();
1400 final int previousOverflowReadableBytes = overflowReadableBytes;
1401 overflowReadableBytes = readableBytes;
1402 int bufferSize = engine.getSession().getApplicationBufferSize() - readableBytes;
1403 if (readableBytes > 0) {
1404 firedChannelRead = true;
1405 ctx.fireChannelRead(decodeOut);
1406
1407 // This buffer was handled, null it out.
1408 decodeOut = null;
1409 if (bufferSize <= 0) {
1410 // It may happen that readableBytes >= engine.getSession().getApplicationBufferSize()
1411 // while there is still more to unwrap, in this case we will just allocate a new buffer
1412 // with the capacity of engine.getSession().getApplicationBufferSize() and call unwrap
1413 // again.
1414 bufferSize = engine.getSession().getApplicationBufferSize();
1415 }
1416 } else {
1417 // This buffer was handled, null it out.
1418 decodeOut.release();
1419 decodeOut = null;
1420 }
1421 if (readableBytes == 0 && previousOverflowReadableBytes == 0) {
1422 // If there is two consecutive loops where we overflow and are not able to consume any data,
1423 // assume the amount of data exceeds the maximum amount for the engine and bail
1424 throw new IllegalStateException("Two consecutive overflows but no content was consumed. " +
1425 SSLSession.class.getSimpleName() + " getApplicationBufferSize: " +
1426 engine.getSession().getApplicationBufferSize() + " maybe too small.");
1427 }
1428 // Allocate a new buffer which can hold all the rest data and loop again.
1429 // TODO: We may want to reconsider how we calculate the length here as we may
1430 // have more then one ssl message to decode.
1431 decodeOut = allocate(ctx, engineType.calculatePendingData(this, bufferSize));
1432 continue;
1433 case CLOSED:
1434 // notify about the CLOSED state of the SSLEngine. See #137
1435 notifyClosure = true;
1436 overflowReadableBytes = -1;
1437 break;
1438 default:
1439 overflowReadableBytes = -1;
1440 break;
1441 }
1442
1443 switch (handshakeStatus) {
1444 case NEED_UNWRAP:
1445 break;
1446 case NEED_WRAP:
1447 // If the wrap operation transitions the status to NOT_HANDSHAKING and there is no more data to
1448 // unwrap then the next call to unwrap will not produce any data. We can avoid the potentially
1449 // costly unwrap operation and break out of the loop.
1450 if (wrapNonAppData(ctx, true) && length == 0) {
1451 break unwrapLoop;
1452 }
1453 break;
1454 case NEED_TASK:
1455 if (!runDelegatedTasks(true)) {
1456 // We scheduled a task on the delegatingTaskExecutor, so stop processing as we will
1457 // resume once the task completes.
1458 //
1459 // We break out of the loop only and do NOT return here as we still may need to notify
1460 // about the closure of the SSLEngine.
1461 //
1462 wrapLater = false;
1463 break unwrapLoop;
1464 }
1465 break;
1466 case FINISHED:
1467 setHandshakeSuccess();
1468 wrapLater = true;
1469
1470 // We 'break' here and NOT 'continue' as android API version 21 has a bug where they consume
1471 // data from the buffer but NOT correctly set the SSLEngineResult.bytesConsumed().
1472 // Because of this it will raise an exception on the next iteration of the for loop on android
1473 // API version 21. Just doing a break will work here as produced and consumed will both be 0
1474 // and so we break out of the complete for (;;) loop and so call decode(...) again later on.
1475 // On other platforms this will have no negative effect as we will just continue with the
1476 // for (;;) loop if something was either consumed or produced.
1477 //
1478 // See:
1479 // - https://github.com/netty/netty/issues/4116
1480 // - https://code.google.com/p/android/issues/detail?id=198639&thanks=198639&ts=1452501203
1481 break;
1482 case NOT_HANDSHAKING:
1483 if (setHandshakeSuccessIfStillHandshaking()) {
1484 wrapLater = true;
1485 continue;
1486 }
1487
1488 // If we are not handshaking and there is no more data to unwrap then the next call to unwrap
1489 // will not produce any data. We can avoid the potentially costly unwrap operation and break
1490 // out of the loop.
1491 if (length == 0) {
1492 break unwrapLoop;
1493 }
1494 break;
1495 default:
1496 throw new IllegalStateException("unknown handshake status: " + handshakeStatus);
1497 }
1498
1499 if (status == Status.BUFFER_UNDERFLOW ||
1500 // If we processed NEED_TASK we should try again even we did not consume or produce anything.
1501 handshakeStatus != HandshakeStatus.NEED_TASK && consumed == 0 && produced == 0) {
1502 if (handshakeStatus == HandshakeStatus.NEED_UNWRAP) {
1503 // The underlying engine is starving so we need to feed it with more data.
1504 // See https://github.com/netty/netty/pull/5039
1505 readIfNeeded(ctx);
1506 }
1507
1508 break;
1509 }
1510 }
1511
1512 if (flushedBeforeHandshake && handshakePromise.isDone()) {
1513 // We need to call wrap(...) in case there was a flush done before the handshake completed to ensure
1514 // we do not stale.
1515 //
1516 // See https://github.com/netty/netty/pull/2437
1517 flushedBeforeHandshake = false;
1518 wrapLater = true;
1519 }
1520
1521 if (wrapLater) {
1522 wrap(ctx, true);
1523 }
1524
1525 if (notifyClosure) {
1526 notifyClosePromise(null);
1527 }
1528 } finally {
1529 if (decodeOut != null) {
1530 if (decodeOut.isReadable()) {
1531 firedChannelRead = true;
1532
1533 ctx.fireChannelRead(decodeOut);
1534 } else {
1535 decodeOut.release();
1536 }
1537 }
1538 }
1539 return originalLength - length;
1540 }
1541
1542 private static ByteBuffer toByteBuffer(ByteBuf out, int index, int len) {
1543 return out.nioBufferCount() == 1 ? out.internalNioBuffer(index, len) :
1544 out.nioBuffer(index, len);
1545 }
1546
1547 private static boolean inEventLoop(Executor executor) {
1548 return executor instanceof EventExecutor && ((EventExecutor) executor).inEventLoop();
1549 }
1550
1551 private static void runAllDelegatedTasks(SSLEngine engine) {
1552 for (;;) {
1553 Runnable task = engine.getDelegatedTask();
1554 if (task == null) {
1555 return;
1556 }
1557 task.run();
1558 }
1559 }
1560
1561 /**
1562 * Will either run the delegated task directly calling {@link Runnable#run()} and return {@code true} or will
1563 * offload the delegated task using {@link Executor#execute(Runnable)} and return {@code false}.
1564 *
1565 * If the task is offloaded it will take care to resume its work on the {@link EventExecutor} once there are no
1566 * more tasks to process.
1567 */
1568 private boolean runDelegatedTasks(boolean inUnwrap) {
1569 if (delegatedTaskExecutor == ImmediateExecutor.INSTANCE || inEventLoop(delegatedTaskExecutor)) {
1570 // We should run the task directly in the EventExecutor thread and not offload at all.
1571 runAllDelegatedTasks(engine);
1572 return true;
1573 } else {
1574 executeDelegatedTasks(inUnwrap);
1575 return false;
1576 }
1577 }
1578
1579 private void executeDelegatedTasks(boolean inUnwrap) {
1580 processTask = true;
1581 try {
1582 delegatedTaskExecutor.execute(new SslTasksRunner(inUnwrap));
1583 } catch (RejectedExecutionException e) {
1584 processTask = false;
1585 throw e;
1586 }
1587 }
1588
1589 /**
1590 * {@link Runnable} that will be scheduled on the {@code delegatedTaskExecutor} and will take care
1591 * of resume work on the {@link EventExecutor} once the task was executed.
1592 */
1593 private final class SslTasksRunner implements Runnable {
1594 private final boolean inUnwrap;
1595
1596 SslTasksRunner(boolean inUnwrap) {
1597 this.inUnwrap = inUnwrap;
1598 }
1599
1600 // Handle errors which happened during task processing.
1601 private void taskError(Throwable e) {
1602 if (inUnwrap) {
1603 // As the error happened while the task was scheduled as part of unwrap(...) we also need to ensure
1604 // we fire it through the pipeline as inbound error to be consistent with what we do in decode(...).
1605 //
1606 // This will also ensure we fail the handshake future and flush all produced data.
1607 try {
1608 handleUnwrapThrowable(ctx, e);
1609 } catch (Throwable cause) {
1610 safeExceptionCaught(cause);
1611 }
1612 } else {
1613 setHandshakeFailure(ctx, e);
1614 forceFlush(ctx);
1615 }
1616 }
1617
1618 // Try to call exceptionCaught(...)
1619 private void safeExceptionCaught(Throwable cause) {
1620 try {
1621 exceptionCaught(ctx, wrapIfNeeded(cause));
1622 } catch (Throwable error) {
1623 ctx.fireExceptionCaught(error);
1624 }
1625 }
1626
1627 private Throwable wrapIfNeeded(Throwable cause) {
1628 if (!inUnwrap) {
1629 // If we are not in unwrap(...) we can just rethrow without wrapping at all.
1630 return cause;
1631 }
1632 // As the exception would have been triggered by an inbound operation we will need to wrap it in a
1633 // DecoderException to mimic what a decoder would do when decode(...) throws.
1634 return cause instanceof DecoderException ? cause : new DecoderException(cause);
1635 }
1636
1637 private void tryDecodeAgain() {
1638 try {
1639 channelRead(ctx, Unpooled.EMPTY_BUFFER);
1640 } catch (Throwable cause) {
1641 safeExceptionCaught(cause);
1642 } finally {
1643 // As we called channelRead(...) we also need to call channelReadComplete(...) which
1644 // will ensure we either call ctx.fireChannelReadComplete() or will trigger a ctx.read() if
1645 // more data is needed.
1646 channelReadComplete0(ctx);
1647 }
1648 }
1649
1650 /**
1651 * Executed after the wrapped {@code task} was executed via {@code delegatedTaskExecutor} to resume work
1652 * on the {@link EventExecutor}.
1653 */
1654 private void resumeOnEventExecutor() {
1655 assert ctx.executor().inEventLoop();
1656
1657 processTask = false;
1658
1659 try {
1660 HandshakeStatus status = engine.getHandshakeStatus();
1661 switch (status) {
1662 // There is another task that needs to be executed and offloaded to the delegatingTaskExecutor.
1663 case NEED_TASK:
1664 executeDelegatedTasks(inUnwrap);
1665
1666 break;
1667
1668 // The handshake finished, lets notify about the completion of it and resume processing.
1669 case FINISHED:
1670 setHandshakeSuccess();
1671
1672 // deliberate fall-through
1673
1674 // Not handshaking anymore, lets notify about the completion if not done yet and resume processing.
1675 case NOT_HANDSHAKING:
1676 setHandshakeSuccessIfStillHandshaking();
1677 try {
1678 // Lets call wrap to ensure we produce the alert if there is any pending and also to
1679 // ensure we flush any queued data..
1680 wrap(ctx, inUnwrap);
1681 } catch (Throwable e) {
1682 taskError(e);
1683 return;
1684 }
1685 if (inUnwrap) {
1686 // If we were in the unwrap call when the task was processed we should also try to unwrap
1687 // non app data first as there may not anything left in the inbound buffer to process.
1688 unwrapNonAppData(ctx);
1689 }
1690
1691 // Flush now as we may have written some data as part of the wrap call.
1692 forceFlush(ctx);
1693
1694 tryDecodeAgain();
1695 break;
1696
1697 // We need more data so lets try to unwrap first and then call decode again which will feed us
1698 // with buffered data (if there is any).
1699 case NEED_UNWRAP:
1700 try {
1701 unwrapNonAppData(ctx);
1702 } catch (SSLException e) {
1703 handleUnwrapThrowable(ctx, e);
1704 return;
1705 }
1706 tryDecodeAgain();
1707 break;
1708
1709 // To make progress we need to call SSLEngine.wrap(...) which may produce more output data
1710 // that will be written to the Channel.
1711 case NEED_WRAP:
1712 try {
1713 if (!wrapNonAppData(ctx, false) && inUnwrap) {
1714 // The handshake finished in wrapNonAppData(...), we need to try call
1715 // unwrapNonAppData(...) as we may have some alert that we should read.
1716 //
1717 // This mimics what we would do when we are calling this method while in unwrap(...).
1718 unwrapNonAppData(ctx);
1719 }
1720
1721 // Flush now as we may have written some data as part of the wrap call.
1722 forceFlush(ctx);
1723 } catch (Throwable e) {
1724 taskError(e);
1725 return;
1726 }
1727
1728 // Now try to feed in more data that we have buffered.
1729 tryDecodeAgain();
1730 break;
1731
1732 default:
1733 // Should never reach here as we handle all cases.
1734 throw new AssertionError();
1735 }
1736 } catch (Throwable cause) {
1737 safeExceptionCaught(cause);
1738 }
1739 }
1740
1741 @Override
1742 public void run() {
1743 try {
1744 runAllDelegatedTasks(engine);
1745
1746 // All tasks were processed.
1747 assert engine.getHandshakeStatus() != HandshakeStatus.NEED_TASK;
1748
1749 // Jump back on the EventExecutor.
1750 ctx.executor().execute(new Runnable() {
1751 @Override
1752 public void run() {
1753 resumeOnEventExecutor();
1754 }
1755 });
1756 } catch (final Throwable cause) {
1757 handleException(cause);
1758 }
1759 }
1760
1761 private void handleException(final Throwable cause) {
1762 if (ctx.executor().inEventLoop()) {
1763 processTask = false;
1764 safeExceptionCaught(cause);
1765 } else {
1766 try {
1767 ctx.executor().execute(new Runnable() {
1768 @Override
1769 public void run() {
1770 processTask = false;
1771 safeExceptionCaught(cause);
1772 }
1773 });
1774 } catch (RejectedExecutionException ignore) {
1775 processTask = false;
1776 // the context itself will handle the rejected exception when try to schedule the operation so
1777 // ignore the RejectedExecutionException
1778 ctx.fireExceptionCaught(cause);
1779 }
1780 }
1781 }
1782 }
1783
1784 /**
1785 * Works around some Android {@link SSLEngine} implementations that skip {@link HandshakeStatus#FINISHED} and
1786 * go straight into {@link HandshakeStatus#NOT_HANDSHAKING} when handshake is finished.
1787 *
1788 * @return {@code true} if and only if the workaround has been applied and thus {@link #handshakeFuture} has been
1789 * marked as success by this method
1790 */
1791 private boolean setHandshakeSuccessIfStillHandshaking() {
1792 if (!handshakePromise.isDone()) {
1793 setHandshakeSuccess();
1794 return true;
1795 }
1796 return false;
1797 }
1798
1799 /**
1800 * Notify all the handshake futures about the successfully handshake
1801 */
1802 private void setHandshakeSuccess() {
1803 handshakePromise.trySuccess(ctx.channel());
1804
1805 if (logger.isDebugEnabled()) {
1806 SSLSession session = engine.getSession();
1807 logger.debug(
1808 "{} HANDSHAKEN: protocol:{} cipher suite:{}",
1809 ctx.channel(),
1810 session.getProtocol(),
1811 session.getCipherSuite());
1812 }
1813 ctx.fireUserEventTriggered(SslHandshakeCompletionEvent.SUCCESS);
1814
1815 if (readDuringHandshake && !ctx.channel().config().isAutoRead()) {
1816 readDuringHandshake = false;
1817 ctx.read();
1818 }
1819 }
1820
1821 /**
1822 * Notify all the handshake futures about the failure during the handshake.
1823 */
1824 private void setHandshakeFailure(ChannelHandlerContext ctx, Throwable cause) {
1825 setHandshakeFailure(ctx, cause, true, true, false);
1826 }
1827
1828 /**
1829 * Notify all the handshake futures about the failure during the handshake.
1830 */
1831 private void setHandshakeFailure(ChannelHandlerContext ctx, Throwable cause, boolean closeInbound,
1832 boolean notify, boolean alwaysFlushAndClose) {
1833 try {
1834 // Release all resources such as internal buffers that SSLEngine
1835 // is managing.
1836 outboundClosed = true;
1837 engine.closeOutbound();
1838
1839 if (closeInbound) {
1840 try {
1841 engine.closeInbound();
1842 } catch (SSLException e) {
1843 if (logger.isDebugEnabled()) {
1844 // only log in debug mode as it most likely harmless and latest chrome still trigger
1845 // this all the time.
1846 //
1847 // See https://github.com/netty/netty/issues/1340
1848 String msg = e.getMessage();
1849 if (msg == null || !(msg.contains("possible truncation attack") ||
1850 msg.contains("closing inbound before receiving peer's close_notify"))) {
1851 logger.debug("{} SSLEngine.closeInbound() raised an exception.", ctx.channel(), e);
1852 }
1853 }
1854 }
1855 }
1856 if (handshakePromise.tryFailure(cause) || alwaysFlushAndClose) {
1857 SslUtils.handleHandshakeFailure(ctx, cause, notify);
1858 }
1859 } finally {
1860 // Ensure we remove and fail all pending writes in all cases and so release memory quickly.
1861 releaseAndFailAll(ctx, cause);
1862 }
1863 }
1864
1865 private void setHandshakeFailureTransportFailure(ChannelHandlerContext ctx, Throwable cause) {
1866 // If TLS control frames fail to write we are in an unknown state and may become out of
1867 // sync with our peer. We give up and close the channel. This will also take care of
1868 // cleaning up any outstanding state (e.g. handshake promise, queued unencrypted data).
1869 try {
1870 SSLException transportFailure = new SSLException("failure when writing TLS control frames", cause);
1871 releaseAndFailAll(ctx, transportFailure);
1872 if (handshakePromise.tryFailure(transportFailure)) {
1873 ctx.fireUserEventTriggered(new SslHandshakeCompletionEvent(transportFailure));
1874 }
1875 } finally {
1876 ctx.close();
1877 }
1878 }
1879
1880 private void releaseAndFailAll(ChannelHandlerContext ctx, Throwable cause) {
1881 if (pendingUnencryptedWrites != null) {
1882 pendingUnencryptedWrites.releaseAndFailAll(ctx, cause);
1883 }
1884 }
1885
1886 private void notifyClosePromise(Throwable cause) {
1887 if (cause == null) {
1888 if (sslClosePromise.trySuccess(ctx.channel())) {
1889 ctx.fireUserEventTriggered(SslCloseCompletionEvent.SUCCESS);
1890 }
1891 } else {
1892 if (sslClosePromise.tryFailure(cause)) {
1893 ctx.fireUserEventTriggered(new SslCloseCompletionEvent(cause));
1894 }
1895 }
1896 }
1897
1898 private void closeOutboundAndChannel(
1899 final ChannelHandlerContext ctx, final ChannelPromise promise, boolean disconnect) throws Exception {
1900 outboundClosed = true;
1901 engine.closeOutbound();
1902
1903 if (!ctx.channel().isActive()) {
1904 if (disconnect) {
1905 ctx.disconnect(promise);
1906 } else {
1907 ctx.close(promise);
1908 }
1909 return;
1910 }
1911
1912 ChannelPromise closeNotifyPromise = ctx.newPromise();
1913 try {
1914 flush(ctx, closeNotifyPromise);
1915 } finally {
1916 if (!closeNotify) {
1917 closeNotify = true;
1918 // It's important that we do not pass the original ChannelPromise to safeClose(...) as when flush(....)
1919 // throws an Exception it will be propagated to the AbstractChannelHandlerContext which will try
1920 // to fail the promise because of this. This will then fail as it was already completed by
1921 // safeClose(...). We create a new ChannelPromise and try to notify the original ChannelPromise
1922 // once it is complete. If we fail to do so we just ignore it as in this case it was failed already
1923 // because of a propagated Exception.
1924 //
1925 // See https://github.com/netty/netty/issues/5931
1926 safeClose(ctx, closeNotifyPromise, ctx.newPromise().addListener(
1927 new ChannelPromiseNotifier(false, promise)));
1928 } else {
1929 /// We already handling the close_notify so just attach the promise to the sslClosePromise.
1930 sslClosePromise.addListener(new FutureListener<Channel>() {
1931 @Override
1932 public void operationComplete(Future<Channel> future) {
1933 promise.setSuccess();
1934 }
1935 });
1936 }
1937 }
1938 }
1939
1940 private void flush(ChannelHandlerContext ctx, ChannelPromise promise) throws Exception {
1941 if (pendingUnencryptedWrites != null) {
1942 pendingUnencryptedWrites.add(Unpooled.EMPTY_BUFFER, promise);
1943 } else {
1944 promise.setFailure(newPendingWritesNullException());
1945 }
1946 flush(ctx);
1947 }
1948
1949 @Override
1950 public void handlerAdded(final ChannelHandlerContext ctx) throws Exception {
1951 this.ctx = ctx;
1952
1953 pendingUnencryptedWrites = new SslHandlerCoalescingBufferQueue(ctx.channel(), 16);
1954 if (ctx.channel().isActive()) {
1955 startHandshakeProcessing();
1956 }
1957 }
1958
1959 private void startHandshakeProcessing() {
1960 if (!handshakeStarted) {
1961 handshakeStarted = true;
1962 if (engine.getUseClientMode()) {
1963 // Begin the initial handshake.
1964 // channelActive() event has been fired already, which means this.channelActive() will
1965 // not be invoked. We have to initialize here instead.
1966 handshake();
1967 }
1968 applyHandshakeTimeout();
1969 }
1970 }
1971
1972 /**
1973 * Performs TLS renegotiation.
1974 */
1975 public Future<Channel> renegotiate() {
1976 ChannelHandlerContext ctx = this.ctx;
1977 if (ctx == null) {
1978 throw new IllegalStateException();
1979 }
1980
1981 return renegotiate(ctx.executor().<Channel>newPromise());
1982 }
1983
1984 /**
1985 * Performs TLS renegotiation.
1986 */
1987 public Future<Channel> renegotiate(final Promise<Channel> promise) {
1988 ObjectUtil.checkNotNull(promise, "promise");
1989
1990 ChannelHandlerContext ctx = this.ctx;
1991 if (ctx == null) {
1992 throw new IllegalStateException();
1993 }
1994
1995 EventExecutor executor = ctx.executor();
1996 if (!executor.inEventLoop()) {
1997 executor.execute(new Runnable() {
1998 @Override
1999 public void run() {
2000 renegotiateOnEventLoop(promise);
2001 }
2002 });
2003 return promise;
2004 }
2005
2006 renegotiateOnEventLoop(promise);
2007 return promise;
2008 }
2009
2010 private void renegotiateOnEventLoop(final Promise<Channel> newHandshakePromise) {
2011 final Promise<Channel> oldHandshakePromise = handshakePromise;
2012 if (!oldHandshakePromise.isDone()) {
2013 // There's no need to handshake because handshake is in progress already.
2014 // Merge the new promise into the old one.
2015 oldHandshakePromise.addListener(new PromiseNotifier<Channel, Future<Channel>>(newHandshakePromise));
2016 } else {
2017 handshakePromise = newHandshakePromise;
2018 handshake();
2019 applyHandshakeTimeout();
2020 }
2021 }
2022
2023 /**
2024 * Performs TLS (re)negotiation.
2025 */
2026 private void handshake() {
2027 if (engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) {
2028 // Not all SSLEngine implementations support calling beginHandshake multiple times while a handshake
2029 // is in progress. See https://github.com/netty/netty/issues/4718.
2030 return;
2031 } else {
2032 if (handshakePromise.isDone()) {
2033 // If the handshake is done already lets just return directly as there is no need to trigger it again.
2034 // This can happen if the handshake(...) was triggered before we called channelActive(...) by a
2035 // flush() that was triggered by a ChannelFutureListener that was added to the ChannelFuture returned
2036 // from the connect(...) method. In this case we will see the flush() happen before we had a chance to
2037 // call fireChannelActive() on the pipeline.
2038 return;
2039 }
2040 }
2041
2042 // Begin handshake.
2043 final ChannelHandlerContext ctx = this.ctx;
2044 try {
2045 engine.beginHandshake();
2046 wrapNonAppData(ctx, false);
2047 } catch (Throwable e) {
2048 setHandshakeFailure(ctx, e);
2049 } finally {
2050 forceFlush(ctx);
2051 }
2052 }
2053
2054 private void applyHandshakeTimeout() {
2055 final Promise<Channel> localHandshakePromise = this.handshakePromise;
2056
2057 // Set timeout if necessary.
2058 final long handshakeTimeoutMillis = this.handshakeTimeoutMillis;
2059 if (handshakeTimeoutMillis <= 0 || localHandshakePromise.isDone()) {
2060 return;
2061 }
2062
2063 final ScheduledFuture<?> timeoutFuture = ctx.executor().schedule(new Runnable() {
2064 @Override
2065 public void run() {
2066 if (localHandshakePromise.isDone()) {
2067 return;
2068 }
2069 SSLException exception =
2070 new SslHandshakeTimeoutException("handshake timed out after " + handshakeTimeoutMillis + "ms");
2071 try {
2072 if (localHandshakePromise.tryFailure(exception)) {
2073 SslUtils.handleHandshakeFailure(ctx, exception, true);
2074 }
2075 } finally {
2076 releaseAndFailAll(ctx, exception);
2077 }
2078 }
2079 }, handshakeTimeoutMillis, TimeUnit.MILLISECONDS);
2080
2081 // Cancel the handshake timeout when handshake is finished.
2082 localHandshakePromise.addListener(new FutureListener<Channel>() {
2083 @Override
2084 public void operationComplete(Future<Channel> f) throws Exception {
2085 timeoutFuture.cancel(false);
2086 }
2087 });
2088 }
2089
2090 private void forceFlush(ChannelHandlerContext ctx) {
2091 needsFlush = false;
2092 ctx.flush();
2093 }
2094
2095 /**
2096 * Issues an initial TLS handshake once connected when used in client-mode
2097 */
2098 @Override
2099 public void channelActive(final ChannelHandlerContext ctx) throws Exception {
2100 if (!startTls) {
2101 startHandshakeProcessing();
2102 }
2103 ctx.fireChannelActive();
2104 }
2105
2106 private void safeClose(
2107 final ChannelHandlerContext ctx, final ChannelFuture flushFuture,
2108 final ChannelPromise promise) {
2109 if (!ctx.channel().isActive()) {
2110 ctx.close(promise);
2111 return;
2112 }
2113
2114 final ScheduledFuture<?> timeoutFuture;
2115 if (!flushFuture.isDone()) {
2116 long closeNotifyTimeout = closeNotifyFlushTimeoutMillis;
2117 if (closeNotifyTimeout > 0) {
2118 // Force-close the connection if close_notify is not fully sent in time.
2119 timeoutFuture = ctx.executor().schedule(new Runnable() {
2120 @Override
2121 public void run() {
2122 // May be done in the meantime as cancel(...) is only best effort.
2123 if (!flushFuture.isDone()) {
2124 logger.warn("{} Last write attempt timed out; force-closing the connection.",
2125 ctx.channel());
2126 addCloseListener(ctx.close(ctx.newPromise()), promise);
2127 }
2128 }
2129 }, closeNotifyTimeout, TimeUnit.MILLISECONDS);
2130 } else {
2131 timeoutFuture = null;
2132 }
2133 } else {
2134 timeoutFuture = null;
2135 }
2136
2137 // Close the connection if close_notify is sent in time.
2138 flushFuture.addListener(new ChannelFutureListener() {
2139 @Override
2140 public void operationComplete(ChannelFuture f)
2141 throws Exception {
2142 if (timeoutFuture != null) {
2143 timeoutFuture.cancel(false);
2144 }
2145 final long closeNotifyReadTimeout = closeNotifyReadTimeoutMillis;
2146 if (closeNotifyReadTimeout <= 0) {
2147 // Trigger the close in all cases to make sure the promise is notified
2148 // See https://github.com/netty/netty/issues/2358
2149 addCloseListener(ctx.close(ctx.newPromise()), promise);
2150 } else {
2151 final ScheduledFuture<?> closeNotifyReadTimeoutFuture;
2152
2153 if (!sslClosePromise.isDone()) {
2154 closeNotifyReadTimeoutFuture = ctx.executor().schedule(new Runnable() {
2155 @Override
2156 public void run() {
2157 if (!sslClosePromise.isDone()) {
2158 logger.debug(
2159 "{} did not receive close_notify in {}ms; force-closing the connection.",
2160 ctx.channel(), closeNotifyReadTimeout);
2161
2162 // Do the close now...
2163 addCloseListener(ctx.close(ctx.newPromise()), promise);
2164 }
2165 }
2166 }, closeNotifyReadTimeout, TimeUnit.MILLISECONDS);
2167 } else {
2168 closeNotifyReadTimeoutFuture = null;
2169 }
2170
2171 // Do the close once the we received the close_notify.
2172 sslClosePromise.addListener(new FutureListener<Channel>() {
2173 @Override
2174 public void operationComplete(Future<Channel> future) throws Exception {
2175 if (closeNotifyReadTimeoutFuture != null) {
2176 closeNotifyReadTimeoutFuture.cancel(false);
2177 }
2178 addCloseListener(ctx.close(ctx.newPromise()), promise);
2179 }
2180 });
2181 }
2182 }
2183 });
2184 }
2185
2186 private static void addCloseListener(ChannelFuture future, ChannelPromise promise) {
2187 // We notify the promise in the ChannelPromiseNotifier as there is a "race" where the close(...) call
2188 // by the timeoutFuture and the close call in the flushFuture listener will be called. Because of
2189 // this we need to use trySuccess() and tryFailure(...) as otherwise we can cause an
2190 // IllegalStateException.
2191 // Also we not want to log if the notification happens as this is expected in some cases.
2192 // See https://github.com/netty/netty/issues/5598
2193 future.addListener(new ChannelPromiseNotifier(false, promise));
2194 }
2195
2196 /**
2197 * Always prefer a direct buffer when it's pooled, so that we reduce the number of memory copies
2198 * in {@link OpenSslEngine}.
2199 */
2200 private ByteBuf allocate(ChannelHandlerContext ctx, int capacity) {
2201 ByteBufAllocator alloc = ctx.alloc();
2202 if (engineType.wantsDirectBuffer) {
2203 return alloc.directBuffer(capacity);
2204 } else {
2205 return alloc.buffer(capacity);
2206 }
2207 }
2208
2209 /**
2210 * Allocates an outbound network buffer for {@link SSLEngine#wrap(ByteBuffer, ByteBuffer)} which can encrypt
2211 * the specified amount of pending bytes.
2212 */
2213 private ByteBuf allocateOutNetBuf(ChannelHandlerContext ctx, int pendingBytes, int numComponents) {
2214 return engineType.allocateWrapBuffer(this, ctx.alloc(), pendingBytes, numComponents);
2215 }
2216
2217 /**
2218 * Each call to SSL_write will introduce about ~100 bytes of overhead. This coalescing queue attempts to increase
2219 * goodput by aggregating the plaintext in chunks of {@link #wrapDataSize}. If many small chunks are written
2220 * this can increase goodput, decrease the amount of calls to SSL_write, and decrease overall encryption operations.
2221 */
2222 private final class SslHandlerCoalescingBufferQueue extends AbstractCoalescingBufferQueue {
2223
2224 SslHandlerCoalescingBufferQueue(Channel channel, int initSize) {
2225 super(channel, initSize);
2226 }
2227
2228 @Override
2229 protected ByteBuf compose(ByteBufAllocator alloc, ByteBuf cumulation, ByteBuf next) {
2230 final int wrapDataSize = SslHandler.this.wrapDataSize;
2231 if (cumulation instanceof CompositeByteBuf) {
2232 CompositeByteBuf composite = (CompositeByteBuf) cumulation;
2233 int numComponents = composite.numComponents();
2234 if (numComponents == 0 ||
2235 !attemptCopyToCumulation(composite.internalComponent(numComponents - 1), next, wrapDataSize)) {
2236 composite.addComponent(true, next);
2237 }
2238 return composite;
2239 }
2240 return attemptCopyToCumulation(cumulation, next, wrapDataSize) ? cumulation :
2241 copyAndCompose(alloc, cumulation, next);
2242 }
2243
2244 @Override
2245 protected ByteBuf composeFirst(ByteBufAllocator allocator, ByteBuf first) {
2246 if (first instanceof CompositeByteBuf) {
2247 CompositeByteBuf composite = (CompositeByteBuf) first;
2248 if (engineType.wantsDirectBuffer) {
2249 first = allocator.directBuffer(composite.readableBytes());
2250 } else {
2251 first = allocator.heapBuffer(composite.readableBytes());
2252 }
2253 try {
2254 first.writeBytes(composite);
2255 } catch (Throwable cause) {
2256 first.release();
2257 PlatformDependent.throwException(cause);
2258 }
2259 composite.release();
2260 }
2261 return first;
2262 }
2263
2264 @Override
2265 protected ByteBuf removeEmptyValue() {
2266 return null;
2267 }
2268 }
2269
2270 private static boolean attemptCopyToCumulation(ByteBuf cumulation, ByteBuf next, int wrapDataSize) {
2271 final int inReadableBytes = next.readableBytes();
2272 final int cumulationCapacity = cumulation.capacity();
2273 if (wrapDataSize - cumulation.readableBytes() >= inReadableBytes &&
2274 // Avoid using the same buffer if next's data would make cumulation exceed the wrapDataSize.
2275 // Only copy if there is enough space available and the capacity is large enough, and attempt to
2276 // resize if the capacity is small.
2277 (cumulation.isWritable(inReadableBytes) && cumulationCapacity >= wrapDataSize ||
2278 cumulationCapacity < wrapDataSize &&
2279 ensureWritableSuccess(cumulation.ensureWritable(inReadableBytes, false)))) {
2280 cumulation.writeBytes(next);
2281 next.release();
2282 return true;
2283 }
2284 return false;
2285 }
2286
2287 private final class LazyChannelPromise extends DefaultPromise<Channel> {
2288
2289 @Override
2290 protected EventExecutor executor() {
2291 if (ctx == null) {
2292 throw new IllegalStateException();
2293 }
2294 return ctx.executor();
2295 }
2296
2297 @Override
2298 protected void checkDeadLock() {
2299 if (ctx == null) {
2300 // If ctx is null the handlerAdded(...) callback was not called, in this case the checkDeadLock()
2301 // method was called from another Thread then the one that is used by ctx.executor(). We need to
2302 // guard against this as a user can see a race if handshakeFuture().sync() is called but the
2303 // handlerAdded(..) method was not yet as it is called from the EventExecutor of the
2304 // ChannelHandlerContext. If we not guard against this super.checkDeadLock() would cause an
2305 // IllegalStateException when trying to call executor().
2306 return;
2307 }
2308 super.checkDeadLock();
2309 }
2310 }
2311 }
2312