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