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