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