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