View Javadoc
1   /*
2    * Copyright 2016 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.internal.tcnative.Buffer;
21  import io.netty.internal.tcnative.SSL;
22  import io.netty.util.AbstractReferenceCounted;
23  import io.netty.util.ReferenceCounted;
24  import io.netty.util.ResourceLeakDetector;
25  import io.netty.util.ResourceLeakDetectorFactory;
26  import io.netty.util.ResourceLeakTracker;
27  import io.netty.util.internal.EmptyArrays;
28  import io.netty.util.internal.PlatformDependent;
29  import io.netty.util.internal.StringUtil;
30  import io.netty.util.internal.ThrowableUtil;
31  import io.netty.util.internal.UnstableApi;
32  import io.netty.util.internal.logging.InternalLogger;
33  import io.netty.util.internal.logging.InternalLoggerFactory;
34  
35  import java.nio.ByteBuffer;
36  import java.nio.ReadOnlyBufferException;
37  import java.security.Principal;
38  import java.security.cert.Certificate;
39  import java.util.ArrayList;
40  import java.util.Arrays;
41  import java.util.Collection;
42  import java.util.Collections;
43  import java.util.HashMap;
44  import java.util.List;
45  import java.util.Map;
46  import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
47  import java.util.concurrent.locks.Lock;
48  
49  import javax.net.ssl.SSLEngine;
50  import javax.net.ssl.SSLEngineResult;
51  import javax.net.ssl.SSLException;
52  import javax.net.ssl.SSLHandshakeException;
53  import javax.net.ssl.SSLParameters;
54  import javax.net.ssl.SSLPeerUnverifiedException;
55  import javax.net.ssl.SSLSession;
56  import javax.net.ssl.SSLSessionBindingEvent;
57  import javax.net.ssl.SSLSessionBindingListener;
58  import javax.net.ssl.SSLSessionContext;
59  import javax.security.cert.X509Certificate;
60  
61  import static io.netty.handler.ssl.OpenSsl.memoryAddress;
62  import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V2;
63  import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V2_HELLO;
64  import static io.netty.handler.ssl.SslUtils.PROTOCOL_SSL_V3;
65  import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1;
66  import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_1;
67  import static io.netty.handler.ssl.SslUtils.PROTOCOL_TLS_V1_2;
68  import static io.netty.handler.ssl.SslUtils.SSL_RECORD_HEADER_LENGTH;
69  import static io.netty.internal.tcnative.SSL.SSL_MAX_PLAINTEXT_LENGTH;
70  import static io.netty.internal.tcnative.SSL.SSL_MAX_RECORD_LENGTH;
71  import static io.netty.util.internal.EmptyArrays.EMPTY_CERTIFICATES;
72  import static io.netty.util.internal.EmptyArrays.EMPTY_JAVAX_X509_CERTIFICATES;
73  import static io.netty.util.internal.ObjectUtil.checkNotNull;
74  import static java.lang.Integer.MAX_VALUE;
75  import static java.lang.Math.min;
76  import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED;
77  import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
78  import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP;
79  import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
80  import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW;
81  import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW;
82  import static javax.net.ssl.SSLEngineResult.Status.CLOSED;
83  import static javax.net.ssl.SSLEngineResult.Status.OK;
84  
85  /**
86   * Implements a {@link SSLEngine} using
87   * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>.
88   * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
89   *
90   * <p>Instances of this class <strong>must</strong> be released before the {@link ReferenceCountedOpenSslContext}
91   * the instance depends upon are released. Otherwise if any method of this class is called which uses the
92   * the {@link ReferenceCountedOpenSslContext} JNI resources the JVM may crash.
93   */
94  public class ReferenceCountedOpenSslEngine extends SSLEngine implements ReferenceCounted, ApplicationProtocolAccessor {
95  
96      private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountedOpenSslEngine.class);
97  
98      private static final SSLException BEGIN_HANDSHAKE_ENGINE_CLOSED = ThrowableUtil.unknownStackTrace(
99              new SSLException("engine closed"), ReferenceCountedOpenSslEngine.class, "beginHandshake()");
100     private static final SSLException HANDSHAKE_ENGINE_CLOSED = ThrowableUtil.unknownStackTrace(
101             new SSLException("engine closed"), ReferenceCountedOpenSslEngine.class, "handshake()");
102     private static final SSLException RENEGOTIATION_UNSUPPORTED =  ThrowableUtil.unknownStackTrace(
103             new SSLException("renegotiation unsupported"), ReferenceCountedOpenSslEngine.class, "beginHandshake()");
104     private static final ResourceLeakDetector<ReferenceCountedOpenSslEngine> leakDetector =
105             ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslEngine.class);
106     private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2 = 0;
107     private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3 = 1;
108     private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1 = 2;
109     private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1 = 3;
110     private static final int OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2 = 4;
111     private static final int[] OPENSSL_OP_NO_PROTOCOLS = {
112             SSL.SSL_OP_NO_SSLv2,
113             SSL.SSL_OP_NO_SSLv3,
114             SSL.SSL_OP_NO_TLSv1,
115             SSL.SSL_OP_NO_TLSv1_1,
116             SSL.SSL_OP_NO_TLSv1_2
117     };
118     /**
119      * <a href="https://www.openssl.org/docs/man1.0.2/crypto/X509_check_host.html">The flags argument is usually 0</a>.
120      */
121     private static final int DEFAULT_HOSTNAME_VALIDATION_FLAGS = 0;
122 
123     /**
124      * Depends upon tcnative ... only use if tcnative is available!
125      */
126     static final int MAX_PLAINTEXT_LENGTH = SSL_MAX_PLAINTEXT_LENGTH;
127     /**
128      * Depends upon tcnative ... only use if tcnative is available!
129      */
130     private static final int MAX_RECORD_SIZE = SSL_MAX_RECORD_LENGTH;
131 
132     private static final AtomicIntegerFieldUpdater<ReferenceCountedOpenSslEngine> DESTROYED_UPDATER =
133             AtomicIntegerFieldUpdater.newUpdater(ReferenceCountedOpenSslEngine.class, "destroyed");
134 
135     private static final String INVALID_CIPHER = "SSL_NULL_WITH_NULL_NULL";
136     private static final SSLEngineResult NEED_UNWRAP_OK = new SSLEngineResult(OK, NEED_UNWRAP, 0, 0);
137     private static final SSLEngineResult NEED_UNWRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0);
138     private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0);
139     private static final SSLEngineResult NEED_WRAP_CLOSED = new SSLEngineResult(CLOSED, NEED_WRAP, 0, 0);
140     private static final SSLEngineResult CLOSED_NOT_HANDSHAKING = new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
141 
142     // OpenSSL state
143     private long ssl;
144     private long networkBIO;
145     private boolean certificateSet;
146 
147     private enum HandshakeState {
148         /**
149          * Not started yet.
150          */
151         NOT_STARTED,
152         /**
153          * Started via unwrap/wrap.
154          */
155         STARTED_IMPLICITLY,
156         /**
157          * Started via {@link #beginHandshake()}.
158          */
159         STARTED_EXPLICITLY,
160         /**
161          * Handshake is finished.
162          */
163         FINISHED
164     }
165 
166     private HandshakeState handshakeState = HandshakeState.NOT_STARTED;
167     private boolean receivedShutdown;
168     private volatile int destroyed;
169     private volatile String applicationProtocol;
170 
171     // Reference Counting
172     private final ResourceLeakTracker<ReferenceCountedOpenSslEngine> leak;
173     private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
174         @Override
175         public ReferenceCounted touch(Object hint) {
176             if (leak != null) {
177                 leak.record(hint);
178             }
179 
180             return ReferenceCountedOpenSslEngine.this;
181         }
182 
183         @Override
184         protected void deallocate() {
185             shutdown();
186             if (leak != null) {
187                 boolean closed = leak.close(ReferenceCountedOpenSslEngine.this);
188                 assert closed;
189             }
190         }
191     };
192 
193     private volatile ClientAuth clientAuth = ClientAuth.NONE;
194 
195     // Updated once a new handshake is started and so the SSLSession reused.
196     private volatile long lastAccessed = -1;
197 
198     private String endPointIdentificationAlgorithm;
199     // Store as object as AlgorithmConstraints only exists since java 7.
200     private Object algorithmConstraints;
201     private List<String> sniHostNames;
202 
203     // Mark as volatile as accessed by checkSniHostnameMatch(...) and also not specify the SNIMatcher type to allow us
204     // using it with java7.
205     private volatile Collection<?> matchers;
206 
207     // SSL Engine status variables
208     private boolean isInboundDone;
209     private boolean outboundClosed;
210 
211     final boolean jdkCompatibilityMode;
212     private final boolean clientMode;
213     final ByteBufAllocator alloc;
214     private final OpenSslEngineMap engineMap;
215     private final OpenSslApplicationProtocolNegotiator apn;
216     private final OpenSslSession session;
217     private final Certificate[] localCerts;
218     private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1];
219     private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1];
220     private final OpenSslKeyMaterialManager keyMaterialManager;
221     private final boolean enableOcsp;
222     private int maxWrapOverhead;
223     private int maxWrapBufferSize;
224 
225     // This is package-private as we set it from OpenSslContext if an exception is thrown during
226     // the verification step.
227     SSLHandshakeException handshakeException;
228 
229     /**
230      * Create a new instance.
231      * @param context Reference count release responsibility is not transferred! The callee still owns this object.
232      * @param alloc The allocator to use.
233      * @param peerHost The peer host name.
234      * @param peerPort The peer port.
235      * @param jdkCompatibilityMode {@code true} to behave like described in
236      *                             https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html.
237      *                             {@code false} allows for partial and/or multiple packets to be process in a single
238      *                             wrap or unwrap call.
239      * @param leakDetection {@code true} to enable leak detection of this object.
240      */
241     ReferenceCountedOpenSslEngine(ReferenceCountedOpenSslContext context, ByteBufAllocator alloc, String peerHost,
242                                   int peerPort, boolean jdkCompatibilityMode, boolean leakDetection) {
243         super(peerHost, peerPort);
244         OpenSsl.ensureAvailability();
245         this.alloc = checkNotNull(alloc, "alloc");
246         apn = (OpenSslApplicationProtocolNegotiator) context.applicationProtocolNegotiator();
247         clientMode = context.isClient();
248         if (PlatformDependent.javaVersion() >= 7 && context.isClient()) {
249             session = new ExtendedOpenSslSession(new DefaultOpenSslSession(context.sessionContext())) {
250                 @Override
251                 public List getRequestedServerNames() {
252                     return Java8SslUtils.getSniHostNames(sniHostNames);
253                 }
254 
255                 @Override
256                 public List<byte[]> getStatusResponses() {
257                     byte[] ocspResponse = null;
258                     if (enableOcsp && clientMode) {
259                         synchronized (ReferenceCountedOpenSslEngine.this) {
260                             if (!isDestroyed()) {
261                                 ocspResponse = SSL.getOcspResponse(ssl);
262                             }
263                         }
264                     }
265                     return ocspResponse == null ?
266                             Collections.<byte[]>emptyList() : Collections.singletonList(ocspResponse);
267                 }
268             };
269         } else {
270             session = new DefaultOpenSslSession(context.sessionContext());
271         }
272         engineMap = context.engineMap;
273         localCerts = context.keyCertChain;
274         keyMaterialManager = context.keyMaterialManager();
275         enableOcsp = context.enableOcsp;
276         this.jdkCompatibilityMode = jdkCompatibilityMode;
277         Lock readerLock = context.ctxLock.readLock();
278         readerLock.lock();
279         final long finalSsl;
280         try {
281             finalSsl = SSL.newSSL(context.ctx, !context.isClient());
282         } finally {
283             readerLock.unlock();
284         }
285         synchronized (this) {
286             ssl = finalSsl;
287             try {
288                 networkBIO = SSL.bioNewByteBuffer(ssl, context.getBioNonApplicationBufferSize());
289 
290                 // Set the client auth mode, this needs to be done via setClientAuth(...) method so we actually call the
291                 // needed JNI methods.
292                 setClientAuth(clientMode ? ClientAuth.NONE : context.clientAuth);
293 
294                 if (context.protocols != null) {
295                     setEnabledProtocols(context.protocols);
296                 }
297 
298                 // Use SNI if peerHost was specified and a valid hostname
299                 // See https://github.com/netty/netty/issues/4746
300                 if (clientMode && SslUtils.isValidHostNameForSNI(peerHost)) {
301                     SSL.setTlsExtHostName(ssl, peerHost);
302                     sniHostNames = Collections.singletonList(peerHost);
303                 }
304 
305                 if (enableOcsp) {
306                     SSL.enableOcsp(ssl);
307                 }
308 
309                 if (!jdkCompatibilityMode) {
310                     SSL.setMode(ssl, SSL.getMode(ssl) | SSL.SSL_MODE_ENABLE_PARTIAL_WRITE);
311                 }
312 
313                 // setMode may impact the overhead.
314                 calculateMaxWrapOverhead();
315             } catch (Throwable cause) {
316                 SSL.freeSSL(ssl);
317                 PlatformDependent.throwException(cause);
318             }
319         }
320 
321         // Only create the leak after everything else was executed and so ensure we don't produce a false-positive for
322         // the ResourceLeakDetector.
323         leak = leakDetection ? leakDetector.track(this) : null;
324     }
325 
326     /**
327      * Sets the OCSP response.
328      */
329     @UnstableApi
330     public void setOcspResponse(byte[] response) {
331         if (!enableOcsp) {
332             throw new IllegalStateException("OCSP stapling is not enabled");
333         }
334 
335         if (clientMode) {
336             throw new IllegalStateException("Not a server SSLEngine");
337         }
338 
339         synchronized (this) {
340             SSL.setOcspResponse(ssl, response);
341         }
342     }
343 
344     /**
345      * Returns the OCSP response or {@code null} if the server didn't provide a stapled OCSP response.
346      */
347     @UnstableApi
348     public byte[] getOcspResponse() {
349         if (!enableOcsp) {
350             throw new IllegalStateException("OCSP stapling is not enabled");
351         }
352 
353         if (!clientMode) {
354             throw new IllegalStateException("Not a client SSLEngine");
355         }
356 
357         synchronized (this) {
358             return SSL.getOcspResponse(ssl);
359         }
360     }
361 
362     @Override
363     public final int refCnt() {
364         return refCnt.refCnt();
365     }
366 
367     @Override
368     public final ReferenceCounted retain() {
369         refCnt.retain();
370         return this;
371     }
372 
373     @Override
374     public final ReferenceCounted retain(int increment) {
375         refCnt.retain(increment);
376         return this;
377     }
378 
379     @Override
380     public final ReferenceCounted touch() {
381         refCnt.touch();
382         return this;
383     }
384 
385     @Override
386     public final ReferenceCounted touch(Object hint) {
387         refCnt.touch(hint);
388         return this;
389     }
390 
391     @Override
392     public final boolean release() {
393         return refCnt.release();
394     }
395 
396     @Override
397     public final boolean release(int decrement) {
398         return refCnt.release(decrement);
399     }
400 
401     @Override
402     public final synchronized SSLSession getHandshakeSession() {
403         // Javadocs state return value should be:
404         // null if this instance is not currently handshaking, or if the current handshake has not
405         // progressed far enough to create a basic SSLSession. Otherwise, this method returns the
406         // SSLSession currently being negotiated.
407         switch(handshakeState) {
408             case NOT_STARTED:
409             case FINISHED:
410                 return null;
411             default:
412                 return session;
413         }
414     }
415 
416     /**
417      * Returns the pointer to the {@code SSL} object for this {@link ReferenceCountedOpenSslEngine}.
418      * Be aware that it is freed as soon as the {@link #release()} or {@link #shutdown()} methods are called.
419      * At this point {@code 0} will be returned.
420      */
421     public final synchronized long sslPointer() {
422         return ssl;
423     }
424 
425     /**
426      * Destroys this engine.
427      */
428     public final synchronized void shutdown() {
429         if (DESTROYED_UPDATER.compareAndSet(this, 0, 1)) {
430             engineMap.remove(ssl);
431             SSL.freeSSL(ssl);
432             ssl = networkBIO = 0;
433 
434             isInboundDone = outboundClosed = true;
435         }
436 
437         // On shutdown clear all errors
438         SSL.clearError();
439     }
440 
441     /**
442      * Write plaintext data to the OpenSSL internal BIO
443      *
444      * Calling this function with src.remaining == 0 is undefined.
445      */
446     private int writePlaintextData(final ByteBuffer src, int len) {
447         final int pos = src.position();
448         final int limit = src.limit();
449         final int sslWrote;
450 
451         if (src.isDirect()) {
452             sslWrote = SSL.writeToSSL(ssl, bufferAddress(src) + pos, len);
453             if (sslWrote > 0) {
454                 src.position(pos + sslWrote);
455             }
456         } else {
457             ByteBuf buf = alloc.directBuffer(len);
458             try {
459                 src.limit(pos + len);
460 
461                 buf.setBytes(0, src);
462                 src.limit(limit);
463 
464                 sslWrote = SSL.writeToSSL(ssl, memoryAddress(buf), len);
465                 if (sslWrote > 0) {
466                     src.position(pos + sslWrote);
467                 } else {
468                     src.position(pos);
469                 }
470             } finally {
471                 buf.release();
472             }
473         }
474         return sslWrote;
475     }
476 
477     /**
478      * Write encrypted data to the OpenSSL network BIO.
479      */
480     private ByteBuf writeEncryptedData(final ByteBuffer src, int len) {
481         final int pos = src.position();
482         if (src.isDirect()) {
483             SSL.bioSetByteBuffer(networkBIO, bufferAddress(src) + pos, len, false);
484         } else {
485             final ByteBuf buf = alloc.directBuffer(len);
486             try {
487                 final int limit = src.limit();
488                 src.limit(pos + len);
489                 buf.writeBytes(src);
490                 // Restore the original position and limit because we don't want to consume from `src`.
491                 src.position(pos);
492                 src.limit(limit);
493 
494                 SSL.bioSetByteBuffer(networkBIO, memoryAddress(buf), len, false);
495                 return buf;
496             } catch (Throwable cause) {
497                 buf.release();
498                 PlatformDependent.throwException(cause);
499             }
500         }
501         return null;
502     }
503 
504     /**
505      * Read plaintext data from the OpenSSL internal BIO
506      */
507     private int readPlaintextData(final ByteBuffer dst) {
508         final int sslRead;
509         final int pos = dst.position();
510         if (dst.isDirect()) {
511             sslRead = SSL.readFromSSL(ssl, bufferAddress(dst) + pos, dst.limit() - pos);
512             if (sslRead > 0) {
513                 dst.position(pos + sslRead);
514             }
515         } else {
516             final int limit = dst.limit();
517             final int len = min(maxEncryptedPacketLength0(), limit - pos);
518             final ByteBuf buf = alloc.directBuffer(len);
519             try {
520                 sslRead = SSL.readFromSSL(ssl, memoryAddress(buf), len);
521                 if (sslRead > 0) {
522                     dst.limit(pos + sslRead);
523                     buf.getBytes(buf.readerIndex(), dst);
524                     dst.limit(limit);
525                 }
526             } finally {
527                 buf.release();
528             }
529         }
530 
531         return sslRead;
532     }
533 
534     /**
535      * Visible only for testing!
536      */
537     final synchronized int maxWrapOverhead() {
538         return maxWrapOverhead;
539     }
540 
541     /**
542      * Visible only for testing!
543      */
544     final synchronized int maxEncryptedPacketLength() {
545         return maxEncryptedPacketLength0();
546     }
547 
548     /**
549      * This method is intentionally not synchronized, only use if you know you are in the EventLoop
550      * thread and visibility on {@link #maxWrapOverhead} is achieved via other synchronized blocks.
551      */
552     final int maxEncryptedPacketLength0() {
553         return maxWrapOverhead + MAX_PLAINTEXT_LENGTH;
554     }
555 
556     /**
557      * This method is intentionally not synchronized, only use if you know you are in the EventLoop
558      * thread and visibility on {@link #maxWrapBufferSize} and {@link #maxWrapOverhead} is achieved
559      * via other synchronized blocks.
560      */
561     final int calculateMaxLengthForWrap(int plaintextLength, int numComponents) {
562         return (int) min(maxWrapBufferSize, plaintextLength + (long) maxWrapOverhead * numComponents);
563     }
564 
565     final synchronized int sslPending() {
566         return sslPending0();
567     }
568 
569     /**
570      * It is assumed this method is called in a synchronized block (or the constructor)!
571      */
572     private void calculateMaxWrapOverhead() {
573         maxWrapOverhead = SSL.getMaxWrapOverhead(ssl);
574 
575         // maxWrapBufferSize must be set after maxWrapOverhead because there is a dependency on this value.
576         // If jdkCompatibility mode is off we allow enough space to encrypt 16 buffers at a time. This could be
577         // configurable in the future if necessary.
578         maxWrapBufferSize = jdkCompatibilityMode ? maxEncryptedPacketLength0() : maxEncryptedPacketLength0() << 4;
579     }
580 
581     private int sslPending0() {
582         // OpenSSL has a limitation where if you call SSL_pending before the handshake is complete OpenSSL will throw a
583         // "called a function you should not call" error. Using the TLS_method instead of SSLv23_method may solve this
584         // issue but this API is only available in 1.1.0+ [1].
585         // [1] https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_new.html
586         return handshakeState != HandshakeState.FINISHED ? 0 : SSL.sslPending(ssl);
587     }
588 
589     private boolean isBytesAvailableEnoughForWrap(int bytesAvailable, int plaintextLength, int numComponents) {
590         return bytesAvailable - (long) maxWrapOverhead * numComponents >= plaintextLength;
591     }
592 
593     @Override
594     public final SSLEngineResult wrap(
595             final ByteBuffer[] srcs, int offset, final int length, final ByteBuffer dst) throws SSLException {
596         // Throw required runtime exceptions
597         if (srcs == null) {
598             throw new IllegalArgumentException("srcs is null");
599         }
600         if (dst == null) {
601             throw new IllegalArgumentException("dst is null");
602         }
603 
604         if (offset >= srcs.length || offset + length > srcs.length) {
605             throw new IndexOutOfBoundsException(
606                     "offset: " + offset + ", length: " + length +
607                             " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
608         }
609 
610         if (dst.isReadOnly()) {
611             throw new ReadOnlyBufferException();
612         }
613 
614         synchronized (this) {
615             if (isOutboundDone()) {
616                 // All drained in the outbound buffer
617                 return isInboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_UNWRAP_CLOSED;
618             }
619 
620             int bytesProduced = 0;
621             ByteBuf bioReadCopyBuf = null;
622             try {
623                 // Setup the BIO buffer so that we directly write the encryption results into dst.
624                 if (dst.isDirect()) {
625                     SSL.bioSetByteBuffer(networkBIO, bufferAddress(dst) + dst.position(), dst.remaining(),
626                             true);
627                 } else {
628                     bioReadCopyBuf = alloc.directBuffer(dst.remaining());
629                     SSL.bioSetByteBuffer(networkBIO, memoryAddress(bioReadCopyBuf), bioReadCopyBuf.writableBytes(),
630                             true);
631                 }
632 
633                 int bioLengthBefore = SSL.bioLengthByteBuffer(networkBIO);
634 
635                 // Explicitly use outboundClosed as we want to drain any bytes that are still present.
636                 if (outboundClosed) {
637                     // If the outbound was closed we want to ensure we can produce the alert to the destination buffer.
638                     // This is true even if we not using jdkCompatibilityMode.
639                     //
640                     // We use a plaintextLength of 2 as we at least want to have an alert fit into it.
641                     // https://tools.ietf.org/html/rfc5246#section-7.2
642                     if (!isBytesAvailableEnoughForWrap(dst.remaining(), 2, 1)) {
643                         return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
644                     }
645 
646                     // There is something left to drain.
647                     // See https://github.com/netty/netty/issues/6260
648                     bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
649                     if (bytesProduced <= 0) {
650                         return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, 0);
651                     }
652                     // It is possible when the outbound was closed there was not enough room in the non-application
653                     // buffers to hold the close_notify. We should keep trying to close until we consume all the data
654                     // OpenSSL can give us.
655                     if (!doSSLShutdown()) {
656                         return newResultMayFinishHandshake(NOT_HANDSHAKING, 0, bytesProduced);
657                     }
658                     bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
659                     return newResultMayFinishHandshake(NEED_WRAP, 0, bytesProduced);
660                 }
661 
662                 // Flush any data that may be implicitly generated by OpenSSL (handshake, close, etc..).
663                 SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
664                 // Prepare OpenSSL to work in server mode and receive handshake
665                 if (handshakeState != HandshakeState.FINISHED) {
666                     if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
667                         // Update accepted so we know we triggered the handshake via wrap
668                         handshakeState = HandshakeState.STARTED_IMPLICITLY;
669                     }
670 
671                     // Flush any data that may have been written implicitly during the handshake by OpenSSL.
672                     bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
673 
674                     if (bytesProduced > 0 && handshakeException != null) {
675                         // TODO(scott): It is possible that when the handshake failed there was not enough room in the
676                         // non-application buffers to hold the alert. We should get all the data before progressing on.
677                         // However I'm not aware of a way to do this with the OpenSSL APIs.
678                         // See https://github.com/netty/netty/issues/6385.
679 
680                         // We produced / consumed some data during the handshake, signal back to the caller.
681                         // If there is a handshake exception and we have produced data, we should send the data before
682                         // we allow handshake() to throw the handshake exception.
683                         return newResult(NEED_WRAP, 0, bytesProduced);
684                     }
685 
686                     status = handshake();
687 
688                     // Handshake may have generated more data, for example if the internal SSL buffer is small
689                     // we may have freed up space by flushing above.
690                     bytesProduced = bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
691 
692                     if (bytesProduced > 0) {
693                         // If we have filled up the dst buffer and we have not finished the handshake we should try to
694                         // wrap again. Otherwise we should only try to wrap again if there is still data pending in
695                         // SSL buffers.
696                         return newResult(mayFinishHandshake(status != FINISHED ?
697                                          bytesProduced == bioLengthBefore ? NEED_WRAP :
698                                          getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO)) : FINISHED),
699                                          0, bytesProduced);
700                     }
701 
702                     if (status == NEED_UNWRAP) {
703                         // Signal if the outbound is done or not.
704                         return isOutboundDone() ? NEED_UNWRAP_CLOSED : NEED_UNWRAP_OK;
705                     }
706 
707                     // Explicit use outboundClosed and not outboundClosed() as we want to drain any bytes that are
708                     // still present.
709                     if (outboundClosed) {
710                         bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
711                         return newResultMayFinishHandshake(status, 0, bytesProduced);
712                     }
713                 }
714 
715                 final int endOffset = offset + length;
716                 if (jdkCompatibilityMode) {
717                     int srcsLen = 0;
718                     for (int i = offset; i < endOffset; ++i) {
719                         final ByteBuffer src = srcs[i];
720                         if (src == null) {
721                             throw new IllegalArgumentException("srcs[" + i + "] is null");
722                         }
723                         if (srcsLen == MAX_PLAINTEXT_LENGTH) {
724                             continue;
725                         }
726 
727                         srcsLen += src.remaining();
728                         if (srcsLen > MAX_PLAINTEXT_LENGTH || srcsLen < 0) {
729                             // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just set it to MAX_PLAINTEXT_LENGTH.
730                             // This also help us to guard against overflow.
731                             // We not break out here as we still need to check for null entries in srcs[].
732                             srcsLen = MAX_PLAINTEXT_LENGTH;
733                         }
734                     }
735 
736                     // jdkCompatibilityMode will only produce a single TLS packet, and we don't aggregate src buffers,
737                     // so we always fix the number of buffers to 1 when checking if the dst buffer is large enough.
738                     if (!isBytesAvailableEnoughForWrap(dst.remaining(), srcsLen, 1)) {
739                         return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
740                     }
741                 }
742 
743                 // There was no pending data in the network BIO -- encrypt any application data
744                 int bytesConsumed = 0;
745                 // Flush any data that may have been written implicitly by OpenSSL in case a shutdown/alert occurs.
746                 bytesProduced = SSL.bioFlushByteBuffer(networkBIO);
747                 for (; offset < endOffset; ++offset) {
748                     final ByteBuffer src = srcs[offset];
749                     final int remaining = src.remaining();
750                     if (remaining == 0) {
751                         continue;
752                     }
753 
754                     final int bytesWritten;
755                     if (jdkCompatibilityMode) {
756                         // Write plaintext application data to the SSL engine. We don't have to worry about checking
757                         // if there is enough space if jdkCompatibilityMode because we only wrap at most
758                         // MAX_PLAINTEXT_LENGTH and we loop over the input before hand and check if there is space.
759                         bytesWritten = writePlaintextData(src, min(remaining, MAX_PLAINTEXT_LENGTH - bytesConsumed));
760                     } else {
761                         // OpenSSL's SSL_write keeps state between calls. We should make sure the amount we attempt to
762                         // write is guaranteed to succeed so we don't have to worry about keeping state consistent
763                         // between calls.
764                         final int availableCapacityForWrap = dst.remaining() - bytesProduced - maxWrapOverhead;
765                         if (availableCapacityForWrap <= 0) {
766                             return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), bytesConsumed,
767                                     bytesProduced);
768                         }
769                         bytesWritten = writePlaintextData(src, min(remaining, availableCapacityForWrap));
770                     }
771 
772                     if (bytesWritten > 0) {
773                         bytesConsumed += bytesWritten;
774 
775                         // Determine how much encrypted data was generated:
776                         final int pendingNow = SSL.bioLengthByteBuffer(networkBIO);
777                         bytesProduced += bioLengthBefore - pendingNow;
778                         bioLengthBefore = pendingNow;
779 
780                         if (jdkCompatibilityMode || bytesProduced == dst.remaining()) {
781                             return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
782                         }
783                     } else {
784                         int sslError = SSL.getError(ssl, bytesWritten);
785                         if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
786                             // This means the connection was shutdown correctly, close inbound and outbound
787                             if (!receivedShutdown) {
788                                 closeAll();
789 
790                                 bytesProduced += bioLengthBefore - SSL.bioLengthByteBuffer(networkBIO);
791 
792                                 // If we have filled up the dst buffer and we have not finished the handshake we should
793                                 // try to wrap again. Otherwise we should only try to wrap again if there is still data
794                                 // pending in SSL buffers.
795                                 SSLEngineResult.HandshakeStatus hs = mayFinishHandshake(
796                                         status != FINISHED ? bytesProduced == dst.remaining() ? NEED_WRAP
797                                                 : getHandshakeStatus(SSL.bioLengthNonApplication(networkBIO))
798                                                 : FINISHED);
799                                 return newResult(hs, bytesConsumed, bytesProduced);
800                             }
801 
802                             return newResult(NOT_HANDSHAKING, bytesConsumed, bytesProduced);
803                         } else if (sslError == SSL.SSL_ERROR_WANT_READ) {
804                             // If there is no pending data to read from BIO we should go back to event loop and try
805                             // to read more data [1]. It is also possible that event loop will detect the socket has
806                             // been closed. [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
807                             return newResult(NEED_UNWRAP, bytesConsumed, bytesProduced);
808                         } else if (sslError == SSL.SSL_ERROR_WANT_WRITE) {
809                             // SSL_ERROR_WANT_WRITE typically means that the underlying transport is not writable
810                             // and we should set the "want write" flag on the selector and try again when the
811                             // underlying transport is writable [1]. However we are not directly writing to the
812                             // underlying transport and instead writing to a BIO buffer. The OpenSsl documentation
813                             // says we should do the following [1]:
814                             //
815                             // "When using a buffering BIO, like a BIO pair, data must be written into or retrieved
816                             // out of the BIO before being able to continue."
817                             //
818                             // In practice this means the destination buffer doesn't have enough space for OpenSSL
819                             // to write encrypted data to. This is an OVERFLOW condition.
820                             // [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
821                             return newResult(BUFFER_OVERFLOW, status, bytesConsumed, bytesProduced);
822                         } else {
823                             // Everything else is considered as error
824                             throw shutdownWithError("SSL_write", sslError);
825                         }
826                     }
827                 }
828                 return newResultMayFinishHandshake(status, bytesConsumed, bytesProduced);
829             } finally {
830                 SSL.bioClearByteBuffer(networkBIO);
831                 if (bioReadCopyBuf == null) {
832                     dst.position(dst.position() + bytesProduced);
833                 } else {
834                     assert bioReadCopyBuf.readableBytes() <= dst.remaining() : "The destination buffer " + dst +
835                             " didn't have enough remaining space to hold the encrypted content in " + bioReadCopyBuf;
836                     dst.put(bioReadCopyBuf.internalNioBuffer(bioReadCopyBuf.readerIndex(), bytesProduced));
837                     bioReadCopyBuf.release();
838                 }
839             }
840         }
841     }
842 
843     private SSLEngineResult newResult(SSLEngineResult.HandshakeStatus hs, int bytesConsumed, int bytesProduced) {
844         return newResult(OK, hs, bytesConsumed, bytesProduced);
845     }
846 
847     private SSLEngineResult newResult(SSLEngineResult.Status status, SSLEngineResult.HandshakeStatus hs,
848                                       int bytesConsumed, int bytesProduced) {
849         // If isOutboundDone, then the data from the network BIO
850         // was the close_notify message and all was consumed we are not required to wait
851         // for the receipt the peer's close_notify message -- shutdown.
852         if (isOutboundDone()) {
853             if (isInboundDone()) {
854                 // If the inbound was done as well, we need to ensure we return NOT_HANDSHAKING to signal we are done.
855                 hs = NOT_HANDSHAKING;
856 
857                 // As the inbound and the outbound is done we can shutdown the engine now.
858                 shutdown();
859             }
860             return new SSLEngineResult(CLOSED, hs, bytesConsumed, bytesProduced);
861         }
862         return new SSLEngineResult(status, hs, bytesConsumed, bytesProduced);
863     }
864 
865     private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.HandshakeStatus hs,
866                                                         int bytesConsumed, int bytesProduced) throws SSLException {
867         return newResult(mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED),
868                          bytesConsumed, bytesProduced);
869     }
870 
871     private SSLEngineResult newResultMayFinishHandshake(SSLEngineResult.Status status,
872                                                         SSLEngineResult.HandshakeStatus hs,
873                                                         int bytesConsumed, int bytesProduced) throws SSLException {
874         return newResult(status, mayFinishHandshake(hs != FINISHED ? getHandshakeStatus() : FINISHED),
875                          bytesConsumed, bytesProduced);
876     }
877 
878     /**
879      * Log the error, shutdown the engine and throw an exception.
880      */
881     private SSLException shutdownWithError(String operations, int sslError) {
882         return shutdownWithError(operations, sslError, SSL.getLastErrorNumber());
883     }
884 
885     private SSLException shutdownWithError(String operation, int sslError, int error) {
886         String errorString = SSL.getErrorString(error);
887         if (logger.isDebugEnabled()) {
888             logger.debug("{} failed with {}: OpenSSL error: {} {}",
889                          operation, sslError, error, errorString);
890         }
891 
892         // There was an internal error -- shutdown
893         shutdown();
894         if (handshakeState == HandshakeState.FINISHED) {
895             return new SSLException(errorString);
896         }
897         return new SSLHandshakeException(errorString);
898     }
899 
900     public final SSLEngineResult unwrap(
901             final ByteBuffer[] srcs, int srcsOffset, final int srcsLength,
902             final ByteBuffer[] dsts, int dstsOffset, final int dstsLength) throws SSLException {
903 
904         // Throw required runtime exceptions
905         if (srcs == null) {
906             throw new NullPointerException("srcs");
907         }
908         if (srcsOffset >= srcs.length
909                 || srcsOffset + srcsLength > srcs.length) {
910             throw new IndexOutOfBoundsException(
911                     "offset: " + srcsOffset + ", length: " + srcsLength +
912                             " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
913         }
914         if (dsts == null) {
915             throw new IllegalArgumentException("dsts is null");
916         }
917         if (dstsOffset >= dsts.length || dstsOffset + dstsLength > dsts.length) {
918             throw new IndexOutOfBoundsException(
919                     "offset: " + dstsOffset + ", length: " + dstsLength +
920                             " (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))");
921         }
922         long capacity = 0;
923         final int dstsEndOffset = dstsOffset + dstsLength;
924         for (int i = dstsOffset; i < dstsEndOffset; i ++) {
925             ByteBuffer dst = dsts[i];
926             if (dst == null) {
927                 throw new IllegalArgumentException("dsts[" + i + "] is null");
928             }
929             if (dst.isReadOnly()) {
930                 throw new ReadOnlyBufferException();
931             }
932             capacity += dst.remaining();
933         }
934 
935         final int srcsEndOffset = srcsOffset + srcsLength;
936         long len = 0;
937         for (int i = srcsOffset; i < srcsEndOffset; i++) {
938             ByteBuffer src = srcs[i];
939             if (src == null) {
940                 throw new IllegalArgumentException("srcs[" + i + "] is null");
941             }
942             len += src.remaining();
943         }
944 
945         synchronized (this) {
946             if (isInboundDone()) {
947                 return isOutboundDone() || isDestroyed() ? CLOSED_NOT_HANDSHAKING : NEED_WRAP_CLOSED;
948             }
949 
950             SSLEngineResult.HandshakeStatus status = NOT_HANDSHAKING;
951             // Prepare OpenSSL to work in server mode and receive handshake
952             if (handshakeState != HandshakeState.FINISHED) {
953                 if (handshakeState != HandshakeState.STARTED_EXPLICITLY) {
954                     // Update accepted so we know we triggered the handshake via wrap
955                     handshakeState = HandshakeState.STARTED_IMPLICITLY;
956                 }
957 
958                 status = handshake();
959                 if (status == NEED_WRAP) {
960                     return NEED_WRAP_OK;
961                 }
962                 // Check if the inbound is considered to be closed if so let us try to wrap again.
963                 if (isInboundDone) {
964                     return NEED_WRAP_CLOSED;
965                 }
966             }
967 
968             int sslPending = sslPending0();
969             int packetLength;
970             // The JDK implies that only a single SSL packet should be processed per unwrap call [1]. If we are in
971             // JDK compatibility mode then we should honor this, but if not we just wrap as much as possible. If there
972             // are multiple records or partial records this may reduce thrashing events through the pipeline.
973             // [1] https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html
974             if (jdkCompatibilityMode) {
975                 if (len < SSL_RECORD_HEADER_LENGTH) {
976                     return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
977                 }
978 
979                 packetLength = SslUtils.getEncryptedPacketLength(srcs, srcsOffset);
980                 if (packetLength == SslUtils.NOT_ENCRYPTED) {
981                     throw new NotSslRecordException("not an SSL/TLS record");
982                 }
983 
984                 final int packetLengthDataOnly = packetLength - SSL_RECORD_HEADER_LENGTH;
985                 if (packetLengthDataOnly > capacity) {
986                     // Not enough space in the destination buffer so signal the caller that the buffer needs to be
987                     // increased.
988                     if (packetLengthDataOnly > MAX_RECORD_SIZE) {
989                         // The packet length MUST NOT exceed 2^14 [1]. However we do accommodate more data to support
990                         // legacy use cases which may violate this condition (e.g. OpenJDK's SslEngineImpl). If the max
991                         // length is exceeded we fail fast here to avoid an infinite loop due to the fact that we
992                         // won't allocate a buffer large enough.
993                         // [1] https://tools.ietf.org/html/rfc5246#section-6.2.1
994                         throw new SSLException("Illegal packet length: " + packetLengthDataOnly + " > " +
995                                                 session.getApplicationBufferSize());
996                     } else {
997                         session.tryExpandApplicationBufferSize(packetLengthDataOnly);
998                     }
999                     return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
1000                 }
1001 
1002                 if (len < packetLength) {
1003                     // We either don't have enough data to read the packet length or not enough for reading the whole
1004                     // packet.
1005                     return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
1006                 }
1007             } else if (len == 0 && sslPending <= 0) {
1008                 return newResultMayFinishHandshake(BUFFER_UNDERFLOW, status, 0, 0);
1009             } else if (capacity == 0) {
1010                 return newResultMayFinishHandshake(BUFFER_OVERFLOW, status, 0, 0);
1011             } else {
1012                 packetLength = (int) min(MAX_VALUE, len);
1013             }
1014 
1015             // This must always be the case when we reached here as if not we returned BUFFER_UNDERFLOW.
1016             assert srcsOffset < srcsEndOffset;
1017 
1018             // This must always be the case if we reached here.
1019             assert capacity > 0;
1020 
1021             // Number of produced bytes
1022             int bytesProduced = 0;
1023             int bytesConsumed = 0;
1024             try {
1025                 srcLoop:
1026                 for (;;) {
1027                     ByteBuffer src = srcs[srcsOffset];
1028                     int remaining = src.remaining();
1029                     final ByteBuf bioWriteCopyBuf;
1030                     int pendingEncryptedBytes;
1031                     if (remaining == 0) {
1032                         if (sslPending <= 0) {
1033                             // We must skip empty buffers as BIO_write will return 0 if asked to write something
1034                             // with length 0.
1035                             if (++srcsOffset >= srcsEndOffset) {
1036                                 break;
1037                             }
1038                             continue;
1039                         } else {
1040                             bioWriteCopyBuf = null;
1041                             pendingEncryptedBytes = SSL.bioLengthByteBuffer(networkBIO);
1042                         }
1043                     } else {
1044                         // Write more encrypted data into the BIO. Ensure we only read one packet at a time as
1045                         // stated in the SSLEngine javadocs.
1046                         pendingEncryptedBytes = min(packetLength, remaining);
1047                         bioWriteCopyBuf = writeEncryptedData(src, pendingEncryptedBytes);
1048                     }
1049                     try {
1050                         for (;;) {
1051                             ByteBuffer dst = dsts[dstsOffset];
1052                             if (!dst.hasRemaining()) {
1053                                 // No space left in the destination buffer, skip it.
1054                                 if (++dstsOffset >= dstsEndOffset) {
1055                                     break srcLoop;
1056                                 }
1057                                 continue;
1058                             }
1059 
1060                             int bytesRead = readPlaintextData(dst);
1061                             // We are directly using the ByteBuffer memory for the write, and so we only know what has
1062                             // been consumed after we let SSL decrypt the data. At this point we should update the
1063                             // number of bytes consumed, update the ByteBuffer position, and release temp ByteBuf.
1064                             int localBytesConsumed = pendingEncryptedBytes - SSL.bioLengthByteBuffer(networkBIO);
1065                             bytesConsumed += localBytesConsumed;
1066                             packetLength -= localBytesConsumed;
1067                             pendingEncryptedBytes -= localBytesConsumed;
1068                             src.position(src.position() + localBytesConsumed);
1069 
1070                             if (bytesRead > 0) {
1071                                 bytesProduced += bytesRead;
1072 
1073                                 if (!dst.hasRemaining()) {
1074                                     sslPending = sslPending0();
1075                                     // Move to the next dst buffer as this one is full.
1076                                     if (++dstsOffset >= dstsEndOffset) {
1077                                         return sslPending > 0 ?
1078                                                 newResult(BUFFER_OVERFLOW, status, bytesConsumed, bytesProduced) :
1079                                                 newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
1080                                                                             bytesConsumed, bytesProduced);
1081                                     }
1082                                 } else if (packetLength == 0 || jdkCompatibilityMode) {
1083                                     // We either consumed all data or we are in jdkCompatibilityMode and have consumed
1084                                     // a single TLS packet and should stop consuming until this method is called again.
1085                                     break srcLoop;
1086                                 }
1087                             } else {
1088                                 int sslError = SSL.getError(ssl, bytesRead);
1089                                 if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) {
1090                                     // break to the outer loop as we want to read more data which means we need to
1091                                     // write more to the BIO.
1092                                     break;
1093                                 } else if (sslError == SSL.SSL_ERROR_ZERO_RETURN) {
1094                                     // This means the connection was shutdown correctly, close inbound and outbound
1095                                     if (!receivedShutdown) {
1096                                         closeAll();
1097                                     }
1098                                     return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status,
1099                                                                        bytesConsumed, bytesProduced);
1100                                 } else {
1101                                     return sslReadErrorResult(sslError, SSL.getLastErrorNumber(), bytesConsumed,
1102                                                               bytesProduced);
1103                                 }
1104                             }
1105                         }
1106 
1107                         if (++srcsOffset >= srcsEndOffset) {
1108                             break;
1109                         }
1110                     } finally {
1111                         if (bioWriteCopyBuf != null) {
1112                             bioWriteCopyBuf.release();
1113                         }
1114                     }
1115                 }
1116             } finally {
1117                 SSL.bioClearByteBuffer(networkBIO);
1118                 rejectRemoteInitiatedRenegotiation();
1119             }
1120 
1121             // Check to see if we received a close_notify message from the peer.
1122             if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) {
1123                 closeAll();
1124             }
1125 
1126             return newResultMayFinishHandshake(isInboundDone() ? CLOSED : OK, status, bytesConsumed, bytesProduced);
1127         }
1128     }
1129 
1130     private SSLEngineResult sslReadErrorResult(int error, int stackError, int bytesConsumed, int bytesProduced)
1131             throws SSLException {
1132         // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the
1133         // BIO first or can just shutdown and throw it now.
1134         // This is needed so we ensure close_notify etc is correctly send to the remote peer.
1135         // See https://github.com/netty/netty/issues/3900
1136         if (SSL.bioLengthNonApplication(networkBIO) > 0) {
1137             if (handshakeException == null && handshakeState != HandshakeState.FINISHED) {
1138                 // we seems to have data left that needs to be transfered and so the user needs
1139                 // call wrap(...). Store the error so we can pick it up later.
1140                 handshakeException = new SSLHandshakeException(SSL.getErrorString(stackError));
1141             }
1142             // We need to clear all errors so we not pick up anything that was left on the stack on the next
1143             // operation. Note that shutdownWithError(...) will cleanup the stack as well so its only needed here.
1144             SSL.clearError();
1145             return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced);
1146         }
1147         throw shutdownWithError("SSL_read", error, stackError);
1148     }
1149 
1150     private void closeAll() throws SSLException {
1151         receivedShutdown = true;
1152         closeOutbound();
1153         closeInbound();
1154     }
1155 
1156     private void rejectRemoteInitiatedRenegotiation() throws SSLHandshakeException {
1157         // As rejectRemoteInitiatedRenegotiation() is called in a finally block we also need to check if we shutdown
1158         // the engine before as otherwise SSL.getHandshakeCount(ssl) will throw an NPE if the passed in ssl is 0.
1159         // See https://github.com/netty/netty/issues/7353
1160         if (!isDestroyed() && SSL.getHandshakeCount(ssl) > 1) {
1161             // TODO: In future versions me may also want to send a fatal_alert to the client and so notify it
1162             // that the renegotiation failed.
1163             shutdown();
1164             throw new SSLHandshakeException("remote-initiated renegotiation not allowed");
1165         }
1166     }
1167 
1168     public final SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts) throws SSLException {
1169         return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length);
1170     }
1171 
1172     private ByteBuffer[] singleSrcBuffer(ByteBuffer src) {
1173         singleSrcBuffer[0] = src;
1174         return singleSrcBuffer;
1175     }
1176 
1177     private void resetSingleSrcBuffer() {
1178         singleSrcBuffer[0] = null;
1179     }
1180 
1181     private ByteBuffer[] singleDstBuffer(ByteBuffer src) {
1182         singleDstBuffer[0] = src;
1183         return singleDstBuffer;
1184     }
1185 
1186     private void resetSingleDstBuffer() {
1187         singleDstBuffer[0] = null;
1188     }
1189 
1190     @Override
1191     public final synchronized SSLEngineResult unwrap(
1192             final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int length) throws SSLException {
1193         try {
1194             return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length);
1195         } finally {
1196             resetSingleSrcBuffer();
1197         }
1198     }
1199 
1200     @Override
1201     public final synchronized SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
1202         try {
1203             return wrap(singleSrcBuffer(src), dst);
1204         } finally {
1205             resetSingleSrcBuffer();
1206         }
1207     }
1208 
1209     @Override
1210     public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
1211         try {
1212             return unwrap(singleSrcBuffer(src), singleDstBuffer(dst));
1213         } finally {
1214             resetSingleSrcBuffer();
1215             resetSingleDstBuffer();
1216         }
1217     }
1218 
1219     @Override
1220     public final synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException {
1221         try {
1222             return unwrap(singleSrcBuffer(src), dsts);
1223         } finally {
1224             resetSingleSrcBuffer();
1225         }
1226     }
1227 
1228     @Override
1229     public final Runnable getDelegatedTask() {
1230         // Currently, we do not delegate SSL computation tasks
1231         // TODO: in the future, possibly create tasks to do encrypt / decrypt async
1232         return null;
1233     }
1234 
1235     @Override
1236     public final synchronized void closeInbound() throws SSLException {
1237         if (isInboundDone) {
1238             return;
1239         }
1240 
1241         isInboundDone = true;
1242 
1243         if (isOutboundDone()) {
1244             // Only call shutdown if there is no outbound data pending.
1245             // See https://github.com/netty/netty/issues/6167
1246             shutdown();
1247         }
1248 
1249         if (handshakeState != HandshakeState.NOT_STARTED && !receivedShutdown) {
1250             throw new SSLException(
1251                     "Inbound closed before receiving peer's close_notify: possible truncation attack?");
1252         }
1253     }
1254 
1255     @Override
1256     public final synchronized boolean isInboundDone() {
1257         return isInboundDone;
1258     }
1259 
1260     @Override
1261     public final synchronized void closeOutbound() {
1262         if (outboundClosed) {
1263             return;
1264         }
1265 
1266         outboundClosed = true;
1267 
1268         if (handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()) {
1269             int mode = SSL.getShutdown(ssl);
1270             if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) {
1271                 doSSLShutdown();
1272             }
1273         } else {
1274             // engine closing before initial handshake
1275             shutdown();
1276         }
1277     }
1278 
1279     /**
1280      * Attempt to call {@link SSL#shutdownSSL(long)}.
1281      * @return {@code false} if the call to {@link SSL#shutdownSSL(long)} was not attempted or returned an error.
1282      */
1283     private boolean doSSLShutdown() {
1284         if (SSL.isInInit(ssl) != 0) {
1285             // Only try to call SSL_shutdown if we are not in the init state anymore.
1286             // Otherwise we will see 'error:140E0197:SSL routines:SSL_shutdown:shutdown while in init' in our logs.
1287             //
1288             // See also http://hg.nginx.org/nginx/rev/062c189fee20
1289             return false;
1290         }
1291         int err = SSL.shutdownSSL(ssl);
1292         if (err < 0) {
1293             int sslErr = SSL.getError(ssl, err);
1294             if (sslErr == SSL.SSL_ERROR_SYSCALL || sslErr == SSL.SSL_ERROR_SSL) {
1295                 if (logger.isDebugEnabled()) {
1296                     int error = SSL.getLastErrorNumber();
1297                     logger.debug("SSL_shutdown failed: OpenSSL error: {} {}", error, SSL.getErrorString(error));
1298                 }
1299                 // There was an internal error -- shutdown
1300                 shutdown();
1301                 return false;
1302             }
1303             SSL.clearError();
1304         }
1305         return true;
1306     }
1307 
1308     @Override
1309     public final synchronized boolean isOutboundDone() {
1310         // Check if there is anything left in the outbound buffer.
1311         // We need to ensure we only call SSL.pendingWrittenBytesInBIO(...) if the engine was not destroyed yet.
1312         return outboundClosed && (networkBIO == 0 || SSL.bioLengthNonApplication(networkBIO) == 0);
1313     }
1314 
1315     @Override
1316     public final String[] getSupportedCipherSuites() {
1317         return OpenSsl.AVAILABLE_CIPHER_SUITES.toArray(new String[0]);
1318     }
1319 
1320     @Override
1321     public final String[] getEnabledCipherSuites() {
1322         final String[] enabled;
1323         synchronized (this) {
1324             if (!isDestroyed()) {
1325                 enabled = SSL.getCiphers(ssl);
1326             } else {
1327                 return EmptyArrays.EMPTY_STRINGS;
1328             }
1329         }
1330         if (enabled == null) {
1331             return EmptyArrays.EMPTY_STRINGS;
1332         } else {
1333             synchronized (this) {
1334                 for (int i = 0; i < enabled.length; i++) {
1335                     String mapped = toJavaCipherSuite(enabled[i]);
1336                     if (mapped != null) {
1337                         enabled[i] = mapped;
1338                     }
1339                 }
1340             }
1341             return enabled;
1342         }
1343     }
1344 
1345     @Override
1346     public final void setEnabledCipherSuites(String[] cipherSuites) {
1347         checkNotNull(cipherSuites, "cipherSuites");
1348 
1349         final StringBuilder buf = new StringBuilder();
1350         for (String c: cipherSuites) {
1351             if (c == null) {
1352                 break;
1353             }
1354 
1355             String converted = CipherSuiteConverter.toOpenSsl(c);
1356             if (converted == null) {
1357                 converted = c;
1358             }
1359 
1360             if (!OpenSsl.isCipherSuiteAvailable(converted)) {
1361                 throw new IllegalArgumentException("unsupported cipher suite: " + c + '(' + converted + ')');
1362             }
1363 
1364             buf.append(converted);
1365             buf.append(':');
1366         }
1367 
1368         if (buf.length() == 0) {
1369             throw new IllegalArgumentException("empty cipher suites");
1370         }
1371         buf.setLength(buf.length() - 1);
1372 
1373         final String cipherSuiteSpec = buf.toString();
1374 
1375         synchronized (this) {
1376             if (!isDestroyed()) {
1377                 try {
1378                     SSL.setCipherSuites(ssl, cipherSuiteSpec);
1379                 } catch (Exception e) {
1380                     throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec, e);
1381                 }
1382             } else {
1383                 throw new IllegalStateException("failed to enable cipher suites: " + cipherSuiteSpec);
1384             }
1385         }
1386     }
1387 
1388     @Override
1389     public final String[] getSupportedProtocols() {
1390         return OpenSsl.SUPPORTED_PROTOCOLS_SET.toArray(new String[0]);
1391     }
1392 
1393     @Override
1394     public final String[] getEnabledProtocols() {
1395         List<String> enabled = new ArrayList<String>(6);
1396         // Seems like there is no way to explicit disable SSLv2Hello in openssl so it is always enabled
1397         enabled.add(PROTOCOL_SSL_V2_HELLO);
1398 
1399         int opts;
1400         synchronized (this) {
1401             if (!isDestroyed()) {
1402                 opts = SSL.getOptions(ssl);
1403             } else {
1404                 return enabled.toArray(new String[0]);
1405             }
1406         }
1407         if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1, PROTOCOL_TLS_V1)) {
1408             enabled.add(PROTOCOL_TLS_V1);
1409         }
1410         if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_1, PROTOCOL_TLS_V1_1)) {
1411             enabled.add(PROTOCOL_TLS_V1_1);
1412         }
1413         if (isProtocolEnabled(opts, SSL.SSL_OP_NO_TLSv1_2, PROTOCOL_TLS_V1_2)) {
1414             enabled.add(PROTOCOL_TLS_V1_2);
1415         }
1416         if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv2, PROTOCOL_SSL_V2)) {
1417             enabled.add(PROTOCOL_SSL_V2);
1418         }
1419         if (isProtocolEnabled(opts, SSL.SSL_OP_NO_SSLv3, PROTOCOL_SSL_V3)) {
1420             enabled.add(PROTOCOL_SSL_V3);
1421         }
1422         return enabled.toArray(new String[0]);
1423     }
1424 
1425     private static boolean isProtocolEnabled(int opts, int disableMask, String protocolString) {
1426         // We also need to check if the actual protocolString is supported as depending on the openssl API
1427         // implementations it may use a disableMask of 0 (BoringSSL is doing this for example).
1428         return (opts & disableMask) == 0 && OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(protocolString);
1429     }
1430 
1431     /**
1432      * {@inheritDoc}
1433      * TLS doesn't support a way to advertise non-contiguous versions from the client's perspective, and the client
1434      * just advertises the max supported version. The TLS protocol also doesn't support all different combinations of
1435      * discrete protocols, and instead assumes contiguous ranges. OpenSSL has some unexpected behavior
1436      * (e.g. handshake failures) if non-contiguous protocols are used even where there is a compatible set of protocols
1437      * and ciphers. For these reasons this method will determine the minimum protocol and the maximum protocol and
1438      * enabled a contiguous range from [min protocol, max protocol] in OpenSSL.
1439      */
1440     @Override
1441     public final void setEnabledProtocols(String[] protocols) {
1442         if (protocols == null) {
1443             // This is correct from the API docs
1444             throw new IllegalArgumentException();
1445         }
1446         int minProtocolIndex = OPENSSL_OP_NO_PROTOCOLS.length;
1447         int maxProtocolIndex = 0;
1448         for (String p: protocols) {
1449             if (!OpenSsl.SUPPORTED_PROTOCOLS_SET.contains(p)) {
1450                 throw new IllegalArgumentException("Protocol " + p + " is not supported.");
1451             }
1452             if (p.equals(PROTOCOL_SSL_V2)) {
1453                 if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) {
1454                     minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2;
1455                 }
1456                 if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2) {
1457                     maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV2;
1458                 }
1459             } else if (p.equals(PROTOCOL_SSL_V3)) {
1460                 if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3) {
1461                     minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3;
1462                 }
1463                 if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3) {
1464                     maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_SSLV3;
1465                 }
1466             } else if (p.equals(PROTOCOL_TLS_V1)) {
1467                 if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1) {
1468                     minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1;
1469                 }
1470                 if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1) {
1471                     maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1;
1472                 }
1473             } else if (p.equals(PROTOCOL_TLS_V1_1)) {
1474                 if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1) {
1475                     minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1;
1476                 }
1477                 if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1) {
1478                     maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_1;
1479                 }
1480             } else if (p.equals(PROTOCOL_TLS_V1_2)) {
1481                 if (minProtocolIndex > OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2) {
1482                     minProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2;
1483                 }
1484                 if (maxProtocolIndex < OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2) {
1485                     maxProtocolIndex = OPENSSL_OP_NO_PROTOCOL_INDEX_TLSv1_2;
1486                 }
1487             }
1488         }
1489         synchronized (this) {
1490             if (!isDestroyed()) {
1491                 // Clear out options which disable protocols
1492                 SSL.clearOptions(ssl, SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1 |
1493                                       SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2);
1494 
1495                 int opts = 0;
1496                 for (int i = 0; i < minProtocolIndex; ++i) {
1497                     opts |= OPENSSL_OP_NO_PROTOCOLS[i];
1498                 }
1499                 assert maxProtocolIndex != MAX_VALUE;
1500                 for (int i = maxProtocolIndex + 1; i < OPENSSL_OP_NO_PROTOCOLS.length; ++i) {
1501                     opts |= OPENSSL_OP_NO_PROTOCOLS[i];
1502                 }
1503 
1504                 // Disable protocols we do not want
1505                 SSL.setOptions(ssl, opts);
1506             } else {
1507                 throw new IllegalStateException("failed to enable protocols: " + Arrays.asList(protocols));
1508             }
1509         }
1510     }
1511 
1512     @Override
1513     public final SSLSession getSession() {
1514         return session;
1515     }
1516 
1517     @Override
1518     public final synchronized void beginHandshake() throws SSLException {
1519         switch (handshakeState) {
1520             case STARTED_IMPLICITLY:
1521                 checkEngineClosed(BEGIN_HANDSHAKE_ENGINE_CLOSED);
1522 
1523                 // A user did not start handshake by calling this method by him/herself,
1524                 // but handshake has been started already by wrap() or unwrap() implicitly.
1525                 // Because it's the user's first time to call this method, it is unfair to
1526                 // raise an exception.  From the user's standpoint, he or she never asked
1527                 // for renegotiation.
1528 
1529                 handshakeState = HandshakeState.STARTED_EXPLICITLY; // Next time this method is invoked by the user,
1530                 calculateMaxWrapOverhead();
1531                 // we should raise an exception.
1532                 break;
1533             case STARTED_EXPLICITLY:
1534                 // Nothing to do as the handshake is not done yet.
1535                 break;
1536             case FINISHED:
1537                 throw RENEGOTIATION_UNSUPPORTED;
1538             case NOT_STARTED:
1539                 handshakeState = HandshakeState.STARTED_EXPLICITLY;
1540                 handshake();
1541                 calculateMaxWrapOverhead();
1542                 break;
1543             default:
1544                 throw new Error();
1545         }
1546     }
1547 
1548     private void checkEngineClosed(SSLException cause) throws SSLException {
1549         if (isDestroyed()) {
1550             throw cause;
1551         }
1552     }
1553 
1554     private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingStatus) {
1555         // Depending on if there is something left in the BIO we need to WRAP or UNWRAP
1556         return pendingStatus > 0 ? NEED_WRAP : NEED_UNWRAP;
1557     }
1558 
1559     private static boolean isEmpty(Object[] arr) {
1560         return arr == null || arr.length == 0;
1561     }
1562 
1563     private static boolean isEmpty(byte[] cert) {
1564         return cert == null || cert.length == 0;
1565     }
1566 
1567     private SSLEngineResult.HandshakeStatus handshake() throws SSLException {
1568         if (handshakeState == HandshakeState.FINISHED) {
1569             return FINISHED;
1570         }
1571         checkEngineClosed(HANDSHAKE_ENGINE_CLOSED);
1572 
1573         // Check if we have a pending handshakeException and if so see if we need to consume all pending data from the
1574         // BIO first or can just shutdown and throw it now.
1575         // This is needed so we ensure close_notify etc is correctly send to the remote peer.
1576         // See https://github.com/netty/netty/issues/3900
1577         SSLHandshakeException exception = handshakeException;
1578         if (exception != null) {
1579             if (SSL.bioLengthNonApplication(networkBIO) > 0) {
1580                 // There is something pending, we need to consume it first via a WRAP so we don't loose anything.
1581                 return NEED_WRAP;
1582             }
1583             // No more data left to send to the remote peer, so null out the exception field, shutdown and throw
1584             // the exception.
1585             handshakeException = null;
1586             shutdown();
1587             throw exception;
1588         }
1589 
1590         // Adding the OpenSslEngine to the OpenSslEngineMap so it can be used in the AbstractCertificateVerifier.
1591         engineMap.add(this);
1592         if (lastAccessed == -1) {
1593             lastAccessed = System.currentTimeMillis();
1594         }
1595 
1596         if (!certificateSet && keyMaterialManager != null) {
1597             certificateSet = true;
1598             keyMaterialManager.setKeyMaterialServerSide(this);
1599         }
1600 
1601         int code = SSL.doHandshake(ssl);
1602         if (code <= 0) {
1603             // Check if we have a pending exception that was created during the handshake and if so throw it after
1604             // shutdown the connection.
1605             if (handshakeException != null) {
1606                 exception = handshakeException;
1607                 handshakeException = null;
1608                 shutdown();
1609                 throw exception;
1610             }
1611 
1612             int sslError = SSL.getError(ssl, code);
1613             if (sslError == SSL.SSL_ERROR_WANT_READ || sslError == SSL.SSL_ERROR_WANT_WRITE) {
1614                 return pendingStatus(SSL.bioLengthNonApplication(networkBIO));
1615             } else {
1616                 // Everything else is considered as error
1617                 throw shutdownWithError("SSL_do_handshake", sslError);
1618             }
1619         }
1620         // if SSL_do_handshake returns > 0 or sslError == SSL.SSL_ERROR_NAME it means the handshake was finished.
1621         session.handshakeFinished();
1622         engineMap.remove(ssl);
1623         return FINISHED;
1624     }
1625 
1626     private SSLEngineResult.HandshakeStatus mayFinishHandshake(SSLEngineResult.HandshakeStatus status)
1627             throws SSLException {
1628         if (status == NOT_HANDSHAKING && handshakeState != HandshakeState.FINISHED) {
1629             // If the status was NOT_HANDSHAKING and we not finished the handshake we need to call
1630             // SSL_do_handshake() again
1631             return handshake();
1632         }
1633         return status;
1634     }
1635 
1636     @Override
1637     public final synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
1638         // Check if we are in the initial handshake phase or shutdown phase
1639         return needPendingStatus() ? pendingStatus(SSL.bioLengthNonApplication(networkBIO)) : NOT_HANDSHAKING;
1640     }
1641 
1642     private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) {
1643         // Check if we are in the initial handshake phase or shutdown phase
1644         return needPendingStatus() ? pendingStatus(pending) : NOT_HANDSHAKING;
1645     }
1646 
1647     private boolean needPendingStatus() {
1648         return handshakeState != HandshakeState.NOT_STARTED && !isDestroyed()
1649                 && (handshakeState != HandshakeState.FINISHED || isInboundDone() || isOutboundDone());
1650     }
1651 
1652     /**
1653      * Converts the specified OpenSSL cipher suite to the Java cipher suite.
1654      */
1655     private String toJavaCipherSuite(String openSslCipherSuite) {
1656         if (openSslCipherSuite == null) {
1657             return null;
1658         }
1659 
1660         String prefix = toJavaCipherSuitePrefix(SSL.getVersion(ssl));
1661         return CipherSuiteConverter.toJava(openSslCipherSuite, prefix);
1662     }
1663 
1664     /**
1665      * Converts the protocol version string returned by {@link SSL#getVersion(long)} to protocol family string.
1666      */
1667     private static String toJavaCipherSuitePrefix(String protocolVersion) {
1668         final char c;
1669         if (protocolVersion == null || protocolVersion.isEmpty()) {
1670             c = 0;
1671         } else {
1672             c = protocolVersion.charAt(0);
1673         }
1674 
1675         switch (c) {
1676             case 'T':
1677                 return "TLS";
1678             case 'S':
1679                 return "SSL";
1680             default:
1681                 return "UNKNOWN";
1682         }
1683     }
1684 
1685     @Override
1686     public final void setUseClientMode(boolean clientMode) {
1687         if (clientMode != this.clientMode) {
1688             throw new UnsupportedOperationException();
1689         }
1690     }
1691 
1692     @Override
1693     public final boolean getUseClientMode() {
1694         return clientMode;
1695     }
1696 
1697     @Override
1698     public final void setNeedClientAuth(boolean b) {
1699         setClientAuth(b ? ClientAuth.REQUIRE : ClientAuth.NONE);
1700     }
1701 
1702     @Override
1703     public final boolean getNeedClientAuth() {
1704         return clientAuth == ClientAuth.REQUIRE;
1705     }
1706 
1707     @Override
1708     public final void setWantClientAuth(boolean b) {
1709         setClientAuth(b ? ClientAuth.OPTIONAL : ClientAuth.NONE);
1710     }
1711 
1712     @Override
1713     public final boolean getWantClientAuth() {
1714         return clientAuth == ClientAuth.OPTIONAL;
1715     }
1716 
1717     /**
1718      * See <a href="https://www.openssl.org/docs/man1.0.2/ssl/SSL_set_verify.html">SSL_set_verify</a> and
1719      * {@link SSL#setVerify(long, int, int)}.
1720      */
1721     @UnstableApi
1722     public final synchronized void setVerify(int verifyMode, int depth) {
1723         SSL.setVerify(ssl, verifyMode, depth);
1724     }
1725 
1726     private void setClientAuth(ClientAuth mode) {
1727         if (clientMode) {
1728             return;
1729         }
1730         synchronized (this) {
1731             if (clientAuth == mode) {
1732                 // No need to issue any JNI calls if the mode is the same
1733                 return;
1734             }
1735             switch (mode) {
1736                 case NONE:
1737                     SSL.setVerify(ssl, SSL.SSL_CVERIFY_NONE, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
1738                     break;
1739                 case REQUIRE:
1740                     SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
1741                     break;
1742                 case OPTIONAL:
1743                     SSL.setVerify(ssl, SSL.SSL_CVERIFY_OPTIONAL, ReferenceCountedOpenSslContext.VERIFY_DEPTH);
1744                     break;
1745                 default:
1746                     throw new Error(mode.toString());
1747             }
1748             clientAuth = mode;
1749         }
1750     }
1751 
1752     @Override
1753     public final void setEnableSessionCreation(boolean b) {
1754         if (b) {
1755             throw new UnsupportedOperationException();
1756         }
1757     }
1758 
1759     @Override
1760     public final boolean getEnableSessionCreation() {
1761         return false;
1762     }
1763 
1764     @Override
1765     public final synchronized SSLParameters getSSLParameters() {
1766         SSLParameters sslParameters = super.getSSLParameters();
1767 
1768         int version = PlatformDependent.javaVersion();
1769         if (version >= 7) {
1770             sslParameters.setEndpointIdentificationAlgorithm(endPointIdentificationAlgorithm);
1771             Java7SslParametersUtils.setAlgorithmConstraints(sslParameters, algorithmConstraints);
1772             if (version >= 8) {
1773                 if (sniHostNames != null) {
1774                     Java8SslUtils.setSniHostNames(sslParameters, sniHostNames);
1775                 }
1776                 if (!isDestroyed()) {
1777                     Java8SslUtils.setUseCipherSuitesOrder(
1778                             sslParameters, (SSL.getOptions(ssl) & SSL.SSL_OP_CIPHER_SERVER_PREFERENCE) != 0);
1779                 }
1780 
1781                 Java8SslUtils.setSNIMatchers(sslParameters, matchers);
1782             }
1783         }
1784         return sslParameters;
1785     }
1786 
1787     @Override
1788     public final synchronized void setSSLParameters(SSLParameters sslParameters) {
1789         int version = PlatformDependent.javaVersion();
1790         if (version >= 7) {
1791             if (sslParameters.getAlgorithmConstraints() != null) {
1792                 throw new IllegalArgumentException("AlgorithmConstraints are not supported.");
1793             }
1794 
1795             if (version >= 8) {
1796                 if (!isDestroyed()) {
1797                     if (clientMode) {
1798                         final List<String> sniHostNames = Java8SslUtils.getSniHostNames(sslParameters);
1799                         for (String name: sniHostNames) {
1800                             SSL.setTlsExtHostName(ssl, name);
1801                         }
1802                         this.sniHostNames = sniHostNames;
1803                     }
1804                     if (Java8SslUtils.getUseCipherSuitesOrder(sslParameters)) {
1805                         SSL.setOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
1806                     } else {
1807                         SSL.clearOptions(ssl, SSL.SSL_OP_CIPHER_SERVER_PREFERENCE);
1808                     }
1809                 }
1810                 matchers = sslParameters.getSNIMatchers();
1811             }
1812 
1813             final String endPointIdentificationAlgorithm = sslParameters.getEndpointIdentificationAlgorithm();
1814             final boolean endPointVerificationEnabled = isEndPointVerificationEnabled(endPointIdentificationAlgorithm);
1815 
1816             final boolean wasEndPointVerificationEnabled =
1817                     isEndPointVerificationEnabled(this.endPointIdentificationAlgorithm);
1818 
1819             if (wasEndPointVerificationEnabled && !endPointVerificationEnabled) {
1820                 // Passing in null will disable hostname verification again so only do so if it was enabled before.
1821                 SSL.setHostNameValidation(ssl, DEFAULT_HOSTNAME_VALIDATION_FLAGS, null);
1822             } else {
1823                 String host = endPointVerificationEnabled ? getPeerHost() : null;
1824                 if (host != null && !host.isEmpty()) {
1825                     SSL.setHostNameValidation(ssl, DEFAULT_HOSTNAME_VALIDATION_FLAGS, host);
1826                 }
1827             }
1828             // If the user asks for hostname verification we must ensure we verify the peer.
1829             // If the user disables hostname verification we leave it up to the user to change the mode manually.
1830             if (clientMode && endPointVerificationEnabled) {
1831                 SSL.setVerify(ssl, SSL.SSL_CVERIFY_REQUIRED, -1);
1832             }
1833 
1834             this.endPointIdentificationAlgorithm = endPointIdentificationAlgorithm;
1835             algorithmConstraints = sslParameters.getAlgorithmConstraints();
1836         }
1837         super.setSSLParameters(sslParameters);
1838     }
1839 
1840     private static boolean isEndPointVerificationEnabled(String endPointIdentificationAlgorithm) {
1841         return endPointIdentificationAlgorithm != null && !endPointIdentificationAlgorithm.isEmpty();
1842     }
1843 
1844     private boolean isDestroyed() {
1845         return destroyed != 0;
1846     }
1847 
1848     final boolean checkSniHostnameMatch(byte[] hostname) {
1849         return Java8SslUtils.checkSniHostnameMatch(matchers, hostname);
1850     }
1851 
1852     @Override
1853     public String getNegotiatedApplicationProtocol() {
1854         return applicationProtocol;
1855     }
1856 
1857     private static long bufferAddress(ByteBuffer b) {
1858         assert b.isDirect();
1859         if (PlatformDependent.hasUnsafe()) {
1860             return PlatformDependent.directBufferAddress(b);
1861         }
1862         return Buffer.address(b);
1863     }
1864 
1865     private final class DefaultOpenSslSession implements OpenSslSession  {
1866         private final OpenSslSessionContext sessionContext;
1867 
1868         // These are guarded by synchronized(OpenSslEngine.this) as handshakeFinished() may be triggered by any
1869         // thread.
1870         private X509Certificate[] x509PeerCerts;
1871         private Certificate[] peerCerts;
1872         private String protocol;
1873         private String cipher;
1874         private byte[] id;
1875         private long creationTime;
1876         private volatile int applicationBufferSize = MAX_PLAINTEXT_LENGTH;
1877 
1878         // lazy init for memory reasons
1879         private Map<String, Object> values;
1880 
1881         DefaultOpenSslSession(OpenSslSessionContext sessionContext) {
1882             this.sessionContext = sessionContext;
1883         }
1884 
1885         private SSLSessionBindingEvent newSSLSessionBindingEvent(String name) {
1886             return new SSLSessionBindingEvent(session, name);
1887         }
1888 
1889         @Override
1890         public byte[] getId() {
1891             synchronized (ReferenceCountedOpenSslEngine.this) {
1892                 if (id == null) {
1893                     return EmptyArrays.EMPTY_BYTES;
1894                 }
1895                 return id.clone();
1896             }
1897         }
1898 
1899         @Override
1900         public SSLSessionContext getSessionContext() {
1901             return sessionContext;
1902         }
1903 
1904         @Override
1905         public long getCreationTime() {
1906             synchronized (ReferenceCountedOpenSslEngine.this) {
1907                 if (creationTime == 0 && !isDestroyed()) {
1908                     creationTime = SSL.getTime(ssl) * 1000L;
1909                 }
1910             }
1911             return creationTime;
1912         }
1913 
1914         @Override
1915         public long getLastAccessedTime() {
1916             long lastAccessed = ReferenceCountedOpenSslEngine.this.lastAccessed;
1917             // if lastAccessed is -1 we will just return the creation time as the handshake was not started yet.
1918             return lastAccessed == -1 ? getCreationTime() : lastAccessed;
1919         }
1920 
1921         @Override
1922         public void invalidate() {
1923             synchronized (ReferenceCountedOpenSslEngine.this) {
1924                 if (!isDestroyed()) {
1925                     SSL.setTimeout(ssl, 0);
1926                 }
1927             }
1928         }
1929 
1930         @Override
1931         public boolean isValid() {
1932             synchronized (ReferenceCountedOpenSslEngine.this) {
1933                 if (!isDestroyed()) {
1934                     return System.currentTimeMillis() - (SSL.getTimeout(ssl) * 1000L) < (SSL.getTime(ssl) * 1000L);
1935                 }
1936             }
1937             return false;
1938         }
1939 
1940         @Override
1941         public void putValue(String name, Object value) {
1942             if (name == null) {
1943                 throw new NullPointerException("name");
1944             }
1945             if (value == null) {
1946                 throw new NullPointerException("value");
1947             }
1948             Map<String, Object> values = this.values;
1949             if (values == null) {
1950                 // Use size of 2 to keep the memory overhead small
1951                 values = this.values = new HashMap<String, Object>(2);
1952             }
1953             Object old = values.put(name, value);
1954             if (value instanceof SSLSessionBindingListener) {
1955                 // Use newSSLSessionBindingEvent so we alway use the wrapper if needed.
1956                 ((SSLSessionBindingListener) value).valueBound(newSSLSessionBindingEvent(name));
1957             }
1958             notifyUnbound(old, name);
1959         }
1960 
1961         @Override
1962         public Object getValue(String name) {
1963             if (name == null) {
1964                 throw new NullPointerException("name");
1965             }
1966             if (values == null) {
1967                 return null;
1968             }
1969             return values.get(name);
1970         }
1971 
1972         @Override
1973         public void removeValue(String name) {
1974             if (name == null) {
1975                 throw new NullPointerException("name");
1976             }
1977             Map<String, Object> values = this.values;
1978             if (values == null) {
1979                 return;
1980             }
1981             Object old = values.remove(name);
1982             notifyUnbound(old, name);
1983         }
1984 
1985         @Override
1986         public String[] getValueNames() {
1987             Map<String, Object> values = this.values;
1988             if (values == null || values.isEmpty()) {
1989                 return EmptyArrays.EMPTY_STRINGS;
1990             }
1991             return values.keySet().toArray(new String[0]);
1992         }
1993 
1994         private void notifyUnbound(Object value, String name) {
1995             if (value instanceof SSLSessionBindingListener) {
1996                 // Use newSSLSessionBindingEvent so we alway use the wrapper if needed.
1997                 ((SSLSessionBindingListener) value).valueUnbound(newSSLSessionBindingEvent(name));
1998             }
1999         }
2000 
2001         /**
2002          * Finish the handshake and so init everything in the {@link OpenSslSession} that should be accessible by
2003          * the user.
2004          */
2005         @Override
2006         public void handshakeFinished() throws SSLException {
2007             synchronized (ReferenceCountedOpenSslEngine.this) {
2008                 if (!isDestroyed()) {
2009                     id = SSL.getSessionId(ssl);
2010                     cipher = toJavaCipherSuite(SSL.getCipherForSSL(ssl));
2011                     protocol = SSL.getVersion(ssl);
2012 
2013                     initPeerCerts();
2014                     selectApplicationProtocol();
2015                     calculateMaxWrapOverhead();
2016 
2017                     handshakeState = HandshakeState.FINISHED;
2018                 } else {
2019                     throw new SSLException("Already closed");
2020                 }
2021             }
2022         }
2023 
2024         /**
2025          * Init peer certificates that can be obtained via {@link #getPeerCertificateChain()}
2026          * and {@link #getPeerCertificates()}.
2027          */
2028         private void initPeerCerts() {
2029             // Return the full chain from the JNI layer.
2030             byte[][] chain = SSL.getPeerCertChain(ssl);
2031             if (clientMode) {
2032                 if (isEmpty(chain)) {
2033                     peerCerts = EMPTY_CERTIFICATES;
2034                     x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES;
2035                 } else {
2036                     peerCerts = new Certificate[chain.length];
2037                     x509PeerCerts = new X509Certificate[chain.length];
2038                     initCerts(chain, 0);
2039                 }
2040             } else {
2041                 // if used on the server side SSL_get_peer_cert_chain(...) will not include the remote peer
2042                 // certificate. We use SSL_get_peer_certificate to get it in this case and add it to our
2043                 // array later.
2044                 //
2045                 // See https://www.openssl.org/docs/ssl/SSL_get_peer_cert_chain.html
2046                 byte[] clientCert = SSL.getPeerCertificate(ssl);
2047                 if (isEmpty(clientCert)) {
2048                     peerCerts = EMPTY_CERTIFICATES;
2049                     x509PeerCerts = EMPTY_JAVAX_X509_CERTIFICATES;
2050                 } else {
2051                     if (isEmpty(chain)) {
2052                         peerCerts = new Certificate[] {new OpenSslX509Certificate(clientCert)};
2053                         x509PeerCerts = new X509Certificate[] {new OpenSslJavaxX509Certificate(clientCert)};
2054                     } else {
2055                         peerCerts = new Certificate[chain.length + 1];
2056                         x509PeerCerts = new X509Certificate[chain.length + 1];
2057                         peerCerts[0] = new OpenSslX509Certificate(clientCert);
2058                         x509PeerCerts[0] = new OpenSslJavaxX509Certificate(clientCert);
2059                         initCerts(chain, 1);
2060                     }
2061                 }
2062             }
2063         }
2064 
2065         private void initCerts(byte[][] chain, int startPos) {
2066             for (int i = 0; i < chain.length; i++) {
2067                 int certPos = startPos + i;
2068                 peerCerts[certPos] = new OpenSslX509Certificate(chain[i]);
2069                 x509PeerCerts[certPos] = new OpenSslJavaxX509Certificate(chain[i]);
2070             }
2071         }
2072 
2073         /**
2074          * Select the application protocol used.
2075          */
2076         private void selectApplicationProtocol() throws SSLException {
2077             ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior = apn.selectedListenerFailureBehavior();
2078             List<String> protocols = apn.protocols();
2079             String applicationProtocol;
2080             switch (apn.protocol()) {
2081                 case NONE:
2082                     break;
2083                 // We always need to check for applicationProtocol == null as the remote peer may not support
2084                 // the TLS extension or may have returned an empty selection.
2085                 case ALPN:
2086                     applicationProtocol = SSL.getAlpnSelected(ssl);
2087                     if (applicationProtocol != null) {
2088                         ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
2089                                 protocols, behavior, applicationProtocol);
2090                     }
2091                     break;
2092                 case NPN:
2093                     applicationProtocol = SSL.getNextProtoNegotiated(ssl);
2094                     if (applicationProtocol != null) {
2095                         ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
2096                                 protocols, behavior, applicationProtocol);
2097                     }
2098                     break;
2099                 case NPN_AND_ALPN:
2100                     applicationProtocol = SSL.getAlpnSelected(ssl);
2101                     if (applicationProtocol == null) {
2102                         applicationProtocol = SSL.getNextProtoNegotiated(ssl);
2103                     }
2104                     if (applicationProtocol != null) {
2105                         ReferenceCountedOpenSslEngine.this.applicationProtocol = selectApplicationProtocol(
2106                                 protocols, behavior, applicationProtocol);
2107                     }
2108                     break;
2109                 default:
2110                     throw new Error();
2111             }
2112         }
2113 
2114         private String selectApplicationProtocol(List<String> protocols,
2115                                                  ApplicationProtocolConfig.SelectedListenerFailureBehavior behavior,
2116                                                  String applicationProtocol) throws SSLException {
2117             if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT) {
2118                 return applicationProtocol;
2119             } else {
2120                 int size = protocols.size();
2121                 assert size > 0;
2122                 if (protocols.contains(applicationProtocol)) {
2123                     return applicationProtocol;
2124                 } else {
2125                     if (behavior == ApplicationProtocolConfig.SelectedListenerFailureBehavior.CHOOSE_MY_LAST_PROTOCOL) {
2126                         return protocols.get(size - 1);
2127                     } else {
2128                         throw new SSLException("unknown protocol " + applicationProtocol);
2129                     }
2130                 }
2131             }
2132         }
2133 
2134         @Override
2135         public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
2136             synchronized (ReferenceCountedOpenSslEngine.this) {
2137                 if (isEmpty(peerCerts)) {
2138                     throw new SSLPeerUnverifiedException("peer not verified");
2139                 }
2140                 return peerCerts.clone();
2141             }
2142         }
2143 
2144         @Override
2145         public Certificate[] getLocalCertificates() {
2146             if (localCerts == null) {
2147                 return null;
2148             }
2149             return localCerts.clone();
2150         }
2151 
2152         @Override
2153         public X509Certificate[] getPeerCertificateChain() throws SSLPeerUnverifiedException {
2154             synchronized (ReferenceCountedOpenSslEngine.this) {
2155                 if (isEmpty(x509PeerCerts)) {
2156                     throw new SSLPeerUnverifiedException("peer not verified");
2157                 }
2158                 return x509PeerCerts.clone();
2159             }
2160         }
2161 
2162         @Override
2163         public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
2164             Certificate[] peer = getPeerCertificates();
2165             // No need for null or length > 0 is needed as this is done in getPeerCertificates()
2166             // already.
2167             return ((java.security.cert.X509Certificate) peer[0]).getSubjectX500Principal();
2168         }
2169 
2170         @Override
2171         public Principal getLocalPrincipal() {
2172             Certificate[] local = localCerts;
2173             if (local == null || local.length == 0) {
2174                 return null;
2175             }
2176             return ((java.security.cert.X509Certificate) local[0]).getIssuerX500Principal();
2177         }
2178 
2179         @Override
2180         public String getCipherSuite() {
2181             synchronized (ReferenceCountedOpenSslEngine.this) {
2182                 if (cipher == null) {
2183                     return INVALID_CIPHER;
2184                 }
2185                 return cipher;
2186             }
2187         }
2188 
2189         @Override
2190         public String getProtocol() {
2191             String protocol = this.protocol;
2192             if (protocol == null) {
2193                 synchronized (ReferenceCountedOpenSslEngine.this) {
2194                     if (!isDestroyed()) {
2195                         protocol = SSL.getVersion(ssl);
2196                     } else {
2197                         protocol = StringUtil.EMPTY_STRING;
2198                     }
2199                 }
2200             }
2201             return protocol;
2202         }
2203 
2204         @Override
2205         public String getPeerHost() {
2206             return ReferenceCountedOpenSslEngine.this.getPeerHost();
2207         }
2208 
2209         @Override
2210         public int getPeerPort() {
2211             return ReferenceCountedOpenSslEngine.this.getPeerPort();
2212         }
2213 
2214         @Override
2215         public int getPacketBufferSize() {
2216             return maxEncryptedPacketLength();
2217         }
2218 
2219         @Override
2220         public int getApplicationBufferSize() {
2221             return applicationBufferSize;
2222         }
2223 
2224         @Override
2225         public void tryExpandApplicationBufferSize(int packetLengthDataOnly) {
2226             if (packetLengthDataOnly > MAX_PLAINTEXT_LENGTH && applicationBufferSize != MAX_RECORD_SIZE) {
2227                 applicationBufferSize = MAX_RECORD_SIZE;
2228             }
2229         }
2230     }
2231 }