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