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.LazyX509Certificate;
21  import io.netty.internal.tcnative.AsyncSSLPrivateKeyMethod;
22  import io.netty.internal.tcnative.CertificateCompressionAlgo;
23  import io.netty.internal.tcnative.CertificateVerifier;
24  import io.netty.internal.tcnative.ResultCallback;
25  import io.netty.internal.tcnative.SSL;
26  import io.netty.internal.tcnative.SSLContext;
27  import io.netty.internal.tcnative.SSLPrivateKeyMethod;
28  import io.netty.util.AbstractReferenceCounted;
29  import io.netty.util.ReferenceCounted;
30  import io.netty.util.ResourceLeakDetector;
31  import io.netty.util.ResourceLeakDetectorFactory;
32  import io.netty.util.ResourceLeakTracker;
33  import io.netty.util.concurrent.Future;
34  import io.netty.util.concurrent.FutureListener;
35  import io.netty.util.internal.EmptyArrays;
36  import io.netty.util.internal.PlatformDependent;
37  import io.netty.util.internal.StringUtil;
38  import io.netty.util.internal.SuppressJava6Requirement;
39  import io.netty.util.internal.SystemPropertyUtil;
40  import io.netty.util.internal.UnstableApi;
41  import io.netty.util.internal.logging.InternalLogger;
42  import io.netty.util.internal.logging.InternalLoggerFactory;
43  
44  import java.security.PrivateKey;
45  import java.security.SignatureException;
46  import java.security.cert.CertPathValidatorException;
47  import java.security.cert.Certificate;
48  import java.security.cert.CertificateExpiredException;
49  import java.security.cert.CertificateNotYetValidException;
50  import java.security.cert.CertificateRevokedException;
51  import java.security.cert.X509Certificate;
52  import java.util.ArrayList;
53  import java.util.Collections;
54  import java.util.LinkedHashSet;
55  import java.util.List;
56  import java.util.Map;
57  import java.util.concurrent.Executor;
58  import java.util.concurrent.locks.Lock;
59  import java.util.concurrent.locks.ReadWriteLock;
60  import java.util.concurrent.locks.ReentrantReadWriteLock;
61  
62  import javax.net.ssl.KeyManager;
63  import javax.net.ssl.KeyManagerFactory;
64  import javax.net.ssl.SSLEngine;
65  import javax.net.ssl.SSLException;
66  import javax.net.ssl.SSLHandshakeException;
67  import javax.net.ssl.TrustManager;
68  import javax.net.ssl.X509ExtendedTrustManager;
69  import javax.net.ssl.X509KeyManager;
70  import javax.net.ssl.X509TrustManager;
71  
72  import static io.netty.handler.ssl.OpenSsl.DEFAULT_CIPHERS;
73  import static io.netty.handler.ssl.OpenSsl.availableJavaCipherSuites;
74  import static io.netty.util.internal.ObjectUtil.checkNotNull;
75  import static io.netty.util.internal.ObjectUtil.checkNonEmpty;
76  import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
77  
78  /**
79   * An implementation of {@link SslContext} which works with libraries that support the
80   * <a href="https://www.openssl.org/">OpenSsl</a> C library API.
81   * <p>Instances of this class must be {@link #release() released} or else native memory will leak!
82   *
83   * <p>Instances of this class <strong>must not</strong> be released before any {@link ReferenceCountedOpenSslEngine}
84   * which depends upon the instance of this class is released. Otherwise if any method of
85   * {@link ReferenceCountedOpenSslEngine} is called which uses this class's JNI resources the JVM may crash.
86   */
87  public abstract class ReferenceCountedOpenSslContext extends SslContext implements ReferenceCounted {
88      private static final InternalLogger logger =
89              InternalLoggerFactory.getInstance(ReferenceCountedOpenSslContext.class);
90  
91      private static final int DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE = Math.max(1,
92              SystemPropertyUtil.getInt("io.netty.handler.ssl.openssl.bioNonApplicationBufferSize",
93                      2048));
94      // Let's use tasks by default but still allow the user to disable it via system property just in case.
95      static final boolean USE_TASKS =
96              SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.useTasks", true);
97      private static final Integer DH_KEY_LENGTH;
98      private static final ResourceLeakDetector<ReferenceCountedOpenSslContext> leakDetector =
99              ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ReferenceCountedOpenSslContext.class);
100 
101     // TODO: Maybe make configurable ?
102     protected static final int VERIFY_DEPTH = 10;
103 
104     static final boolean CLIENT_ENABLE_SESSION_TICKET =
105             SystemPropertyUtil.getBoolean("jdk.tls.client.enableSessionTicketExtension", false);
106 
107     static final boolean CLIENT_ENABLE_SESSION_TICKET_TLSV13 =
108             SystemPropertyUtil.getBoolean("jdk.tls.client.enableSessionTicketExtension", true);
109 
110     static final boolean SERVER_ENABLE_SESSION_TICKET =
111             SystemPropertyUtil.getBoolean("jdk.tls.server.enableSessionTicketExtension", false);
112 
113      static final boolean SERVER_ENABLE_SESSION_TICKET_TLSV13 =
114             SystemPropertyUtil.getBoolean("jdk.tls.server.enableSessionTicketExtension", true);
115 
116     static final boolean SERVER_ENABLE_SESSION_CACHE =
117             SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.sessionCacheServer", true);
118     static final boolean CLIENT_ENABLE_SESSION_CACHE =
119             SystemPropertyUtil.getBoolean("io.netty.handler.ssl.openssl.sessionCacheClient", true);
120 
121     /**
122      * The OpenSSL SSL_CTX object.
123      *
124      * <strong>{@link #ctxLock} must be hold while using ctx!</strong>
125      */
126     protected long ctx;
127     private final List<String> unmodifiableCiphers;
128     private final OpenSslApplicationProtocolNegotiator apn;
129     private final int mode;
130 
131     // Reference Counting
132     private final ResourceLeakTracker<ReferenceCountedOpenSslContext> leak;
133     private final AbstractReferenceCounted refCnt = new AbstractReferenceCounted() {
134         @Override
135         public ReferenceCounted touch(Object hint) {
136             if (leak != null) {
137                 leak.record(hint);
138             }
139 
140             return ReferenceCountedOpenSslContext.this;
141         }
142 
143         @Override
144         protected void deallocate() {
145             destroy();
146             if (leak != null) {
147                 boolean closed = leak.close(ReferenceCountedOpenSslContext.this);
148                 assert closed;
149             }
150         }
151     };
152 
153     final Certificate[] keyCertChain;
154     final ClientAuth clientAuth;
155     final String[] protocols;
156     final boolean enableOcsp;
157     final OpenSslEngineMap engineMap = new DefaultOpenSslEngineMap();
158     final ReadWriteLock ctxLock = new ReentrantReadWriteLock();
159 
160     private volatile int bioNonApplicationBufferSize = DEFAULT_BIO_NON_APPLICATION_BUFFER_SIZE;
161 
162     @SuppressWarnings("deprecation")
163     static final OpenSslApplicationProtocolNegotiator NONE_PROTOCOL_NEGOTIATOR =
164             new OpenSslApplicationProtocolNegotiator() {
165                 @Override
166                 public ApplicationProtocolConfig.Protocol protocol() {
167                     return ApplicationProtocolConfig.Protocol.NONE;
168                 }
169 
170                 @Override
171                 public List<String> protocols() {
172                     return Collections.emptyList();
173                 }
174 
175                 @Override
176                 public ApplicationProtocolConfig.SelectorFailureBehavior selectorFailureBehavior() {
177                     return ApplicationProtocolConfig.SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL;
178                 }
179 
180                 @Override
181                 public ApplicationProtocolConfig.SelectedListenerFailureBehavior selectedListenerFailureBehavior() {
182                     return ApplicationProtocolConfig.SelectedListenerFailureBehavior.ACCEPT;
183                 }
184             };
185 
186     static {
187         Integer dhLen = null;
188 
189         try {
190             String dhKeySize = SystemPropertyUtil.get("jdk.tls.ephemeralDHKeySize");
191             if (dhKeySize != null) {
192                 try {
193                     dhLen = Integer.valueOf(dhKeySize);
194                 } catch (NumberFormatException e) {
195                     logger.debug("ReferenceCountedOpenSslContext supports -Djdk.tls.ephemeralDHKeySize={int}, but got: "
196                             + dhKeySize);
197                 }
198             }
199         } catch (Throwable ignore) {
200             // ignore
201         }
202         DH_KEY_LENGTH = dhLen;
203     }
204 
205     final boolean tlsFalseStart;
206 
207     ReferenceCountedOpenSslContext(Iterable<String> ciphers, CipherSuiteFilter cipherFilter,
208                                    OpenSslApplicationProtocolNegotiator apn, int mode, Certificate[] keyCertChain,
209                                    ClientAuth clientAuth, String[] protocols, boolean startTls, boolean enableOcsp,
210                                    boolean leakDetection, Map.Entry<SslContextOption<?>, Object>... ctxOptions)
211             throws SSLException {
212         super(startTls);
213 
214         OpenSsl.ensureAvailability();
215 
216         if (enableOcsp && !OpenSsl.isOcspSupported()) {
217             throw new IllegalStateException("OCSP is not supported.");
218         }
219 
220         if (mode != SSL.SSL_MODE_SERVER && mode != SSL.SSL_MODE_CLIENT) {
221             throw new IllegalArgumentException("mode most be either SSL.SSL_MODE_SERVER or SSL.SSL_MODE_CLIENT");
222         }
223 
224         boolean tlsFalseStart = false;
225         boolean useTasks = USE_TASKS;
226         OpenSslPrivateKeyMethod privateKeyMethod = null;
227         OpenSslAsyncPrivateKeyMethod asyncPrivateKeyMethod = null;
228         OpenSslCertificateCompressionConfig certCompressionConfig = null;
229         Integer maxCertificateList = null;
230 
231         if (ctxOptions != null) {
232             for (Map.Entry<SslContextOption<?>, Object> ctxOpt : ctxOptions) {
233                 SslContextOption<?> option = ctxOpt.getKey();
234 
235                 if (option == OpenSslContextOption.TLS_FALSE_START) {
236                     tlsFalseStart = (Boolean) ctxOpt.getValue();
237                 } else if (option == OpenSslContextOption.USE_TASKS) {
238                     useTasks = (Boolean) ctxOpt.getValue();
239                 } else if (option == OpenSslContextOption.PRIVATE_KEY_METHOD) {
240                     privateKeyMethod = (OpenSslPrivateKeyMethod) ctxOpt.getValue();
241                 } else if (option == OpenSslContextOption.ASYNC_PRIVATE_KEY_METHOD) {
242                     asyncPrivateKeyMethod = (OpenSslAsyncPrivateKeyMethod) ctxOpt.getValue();
243                 } else if (option == OpenSslContextOption.CERTIFICATE_COMPRESSION_ALGORITHMS) {
244                     certCompressionConfig = (OpenSslCertificateCompressionConfig) ctxOpt.getValue();
245                 } else if (option == OpenSslContextOption.MAX_CERTIFICATE_LIST_BYTES) {
246                     maxCertificateList = (Integer) ctxOpt.getValue();
247                 } else {
248                     logger.debug("Skipping unsupported " + SslContextOption.class.getSimpleName()
249                             + ": " + ctxOpt.getKey());
250                 }
251             }
252         }
253         if (privateKeyMethod != null && asyncPrivateKeyMethod != null) {
254             throw new IllegalArgumentException("You can either only use "
255                     + OpenSslAsyncPrivateKeyMethod.class.getSimpleName() + " or "
256                     + OpenSslPrivateKeyMethod.class.getSimpleName());
257         }
258 
259         this.tlsFalseStart = tlsFalseStart;
260 
261         leak = leakDetection ? leakDetector.track(this) : null;
262         this.mode = mode;
263         this.clientAuth = isServer() ? checkNotNull(clientAuth, "clientAuth") : ClientAuth.NONE;
264         this.protocols = protocols == null ? OpenSsl.defaultProtocols(mode == SSL.SSL_MODE_CLIENT) : protocols;
265         this.enableOcsp = enableOcsp;
266 
267         this.keyCertChain = keyCertChain == null ? null : keyCertChain.clone();
268 
269         String[] suites = checkNotNull(cipherFilter, "cipherFilter").filterCipherSuites(
270                 ciphers, DEFAULT_CIPHERS, availableJavaCipherSuites());
271         // Filter out duplicates.
272         LinkedHashSet<String> suitesSet = new LinkedHashSet<String>(suites.length);
273         Collections.addAll(suitesSet, suites);
274         unmodifiableCiphers = new ArrayList<String>(suitesSet);
275 
276         this.apn = checkNotNull(apn, "apn");
277 
278         // Create a new SSL_CTX and configure it.
279         boolean success = false;
280         try {
281             boolean tlsv13Supported = OpenSsl.isTlsv13Supported();
282 
283             try {
284                 int protocolOpts = SSL.SSL_PROTOCOL_SSLV3 | SSL.SSL_PROTOCOL_TLSV1 |
285                         SSL.SSL_PROTOCOL_TLSV1_1 | SSL.SSL_PROTOCOL_TLSV1_2;
286                 if (tlsv13Supported) {
287                     protocolOpts |= SSL.SSL_PROTOCOL_TLSV1_3;
288                 }
289                 ctx = SSLContext.make(protocolOpts, mode);
290             } catch (Exception e) {
291                 throw new SSLException("failed to create an SSL_CTX", e);
292             }
293 
294             StringBuilder cipherBuilder = new StringBuilder();
295             StringBuilder cipherTLSv13Builder = new StringBuilder();
296 
297             /* List the ciphers that are permitted to negotiate. */
298             try {
299                 if (unmodifiableCiphers.isEmpty()) {
300                     // Set non TLSv1.3 ciphers.
301                     SSLContext.setCipherSuite(ctx, StringUtil.EMPTY_STRING, false);
302                     if (tlsv13Supported) {
303                         // Set TLSv1.3 ciphers.
304                         SSLContext.setCipherSuite(ctx, StringUtil.EMPTY_STRING, true);
305                     }
306                 } else {
307                     CipherSuiteConverter.convertToCipherStrings(
308                             unmodifiableCiphers, cipherBuilder, cipherTLSv13Builder, OpenSsl.isBoringSSL());
309 
310                     // Set non TLSv1.3 ciphers.
311                     SSLContext.setCipherSuite(ctx, cipherBuilder.toString(), false);
312                     if (tlsv13Supported) {
313                         // Set TLSv1.3 ciphers.
314                         SSLContext.setCipherSuite(ctx,
315                                 OpenSsl.checkTls13Ciphers(logger, cipherTLSv13Builder.toString()), true);
316                     }
317                 }
318             } catch (SSLException e) {
319                 throw e;
320             } catch (Exception e) {
321                 throw new SSLException("failed to set cipher suite: " + unmodifiableCiphers, e);
322             }
323 
324             int options = SSLContext.getOptions(ctx) |
325                     SSL.SSL_OP_NO_SSLv2 |
326                     SSL.SSL_OP_NO_SSLv3 |
327                     // Disable TLSv1 and TLSv1.1 by default as these are not considered secure anymore
328                     // and the JDK is doing the same:
329                     // https://www.oracle.com/java/technologies/javase/8u291-relnotes.html
330                     SSL.SSL_OP_NO_TLSv1 |
331                     SSL.SSL_OP_NO_TLSv1_1 |
332 
333                     SSL.SSL_OP_CIPHER_SERVER_PREFERENCE |
334 
335                     // We do not support compression at the moment so we should explicitly disable it.
336                     SSL.SSL_OP_NO_COMPRESSION |
337 
338                     // Disable ticket support by default to be more inline with SSLEngineImpl of the JDK.
339                     // This also let SSLSession.getId() work the same way for the JDK implementation and the
340                     // OpenSSLEngine. If tickets are supported SSLSession.getId() will only return an ID on the
341                     // server-side if it could make use of tickets.
342                     SSL.SSL_OP_NO_TICKET;
343 
344             if (cipherBuilder.length() == 0) {
345                 // No ciphers that are compatible with SSLv2 / SSLv3 / TLSv1 / TLSv1.1 / TLSv1.2
346                 options |= SSL.SSL_OP_NO_SSLv2 | SSL.SSL_OP_NO_SSLv3 | SSL.SSL_OP_NO_TLSv1
347                         | SSL.SSL_OP_NO_TLSv1_1 | SSL.SSL_OP_NO_TLSv1_2;
348             }
349 
350             if (!tlsv13Supported) {
351                 // Explicit disable TLSv1.3
352                 // See https://github.com/netty/netty/issues/12968
353                 options |= SSL.SSL_OP_NO_TLSv1_3;
354             }
355 
356             SSLContext.setOptions(ctx, options);
357 
358             // We need to enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER as the memory address may change between
359             // calling OpenSSLEngine.wrap(...).
360             // See https://github.com/netty/netty-tcnative/issues/100
361             SSLContext.setMode(ctx, SSLContext.getMode(ctx) | SSL.SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
362 
363             if (DH_KEY_LENGTH != null) {
364                 SSLContext.setTmpDHLength(ctx, DH_KEY_LENGTH);
365             }
366 
367             List<String> nextProtoList = apn.protocols();
368             /* Set next protocols for next protocol negotiation extension, if specified */
369             if (!nextProtoList.isEmpty()) {
370                 String[] appProtocols = nextProtoList.toArray(EmptyArrays.EMPTY_STRINGS);
371                 int selectorBehavior = opensslSelectorFailureBehavior(apn.selectorFailureBehavior());
372 
373                 switch (apn.protocol()) {
374                     case NPN:
375                         SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
376                         break;
377                     case ALPN:
378                         SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
379                         break;
380                     case NPN_AND_ALPN:
381                         SSLContext.setNpnProtos(ctx, appProtocols, selectorBehavior);
382                         SSLContext.setAlpnProtos(ctx, appProtocols, selectorBehavior);
383                         break;
384                     default:
385                         throw new Error();
386                 }
387             }
388 
389             if (enableOcsp) {
390                 SSLContext.enableOcsp(ctx, isClient());
391             }
392 
393             SSLContext.setUseTasks(ctx, useTasks);
394             if (privateKeyMethod != null) {
395                 SSLContext.setPrivateKeyMethod(ctx, new PrivateKeyMethod(engineMap, privateKeyMethod));
396             }
397             if (asyncPrivateKeyMethod != null) {
398                 SSLContext.setPrivateKeyMethod(ctx, new AsyncPrivateKeyMethod(engineMap, asyncPrivateKeyMethod));
399             }
400             if (certCompressionConfig != null) {
401                 for (OpenSslCertificateCompressionConfig.AlgorithmConfig configPair : certCompressionConfig) {
402                     final CertificateCompressionAlgo algo = new CompressionAlgorithm(engineMap, configPair.algorithm());
403                     switch (configPair.mode()) {
404                         case Decompress:
405                             SSLContext.addCertificateCompressionAlgorithm(
406                                     ctx, SSL.SSL_CERT_COMPRESSION_DIRECTION_DECOMPRESS, algo);
407                             break;
408                         case Compress:
409                             SSLContext.addCertificateCompressionAlgorithm(
410                                     ctx, SSL.SSL_CERT_COMPRESSION_DIRECTION_COMPRESS, algo);
411                             break;
412                         case Both:
413                             SSLContext.addCertificateCompressionAlgorithm(
414                                     ctx, SSL.SSL_CERT_COMPRESSION_DIRECTION_BOTH, algo);
415                             break;
416                         default:
417                             throw new IllegalStateException();
418                     }
419                 }
420             }
421             if (maxCertificateList != null) {
422                 SSLContext.setMaxCertList(ctx, maxCertificateList);
423             }
424             // Set the curves.
425             SSLContext.setCurvesList(ctx, OpenSsl.NAMED_GROUPS);
426             success = true;
427         } finally {
428             if (!success) {
429                 release();
430             }
431         }
432     }
433 
434     private static int opensslSelectorFailureBehavior(ApplicationProtocolConfig.SelectorFailureBehavior behavior) {
435         switch (behavior) {
436             case NO_ADVERTISE:
437                 return SSL.SSL_SELECTOR_FAILURE_NO_ADVERTISE;
438             case CHOOSE_MY_LAST_PROTOCOL:
439                 return SSL.SSL_SELECTOR_FAILURE_CHOOSE_MY_LAST_PROTOCOL;
440             default:
441                 throw new Error();
442         }
443     }
444 
445     @Override
446     public final List<String> cipherSuites() {
447         return unmodifiableCiphers;
448     }
449 
450     @Override
451     public ApplicationProtocolNegotiator applicationProtocolNegotiator() {
452         return apn;
453     }
454 
455     @Override
456     public final boolean isClient() {
457         return mode == SSL.SSL_MODE_CLIENT;
458     }
459 
460     @Override
461     public final SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort) {
462         return newEngine0(alloc, peerHost, peerPort, true);
463     }
464 
465     @Override
466     protected final SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) {
467         return new SslHandler(newEngine0(alloc, null, -1, false), startTls);
468     }
469 
470     @Override
471     protected final SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls) {
472         return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), startTls);
473     }
474 
475     @Override
476     protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls, Executor executor) {
477         return new SslHandler(newEngine0(alloc, null, -1, false), startTls, executor);
478     }
479 
480     @Override
481     protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort,
482                                     boolean startTls, Executor executor) {
483         return new SslHandler(newEngine0(alloc, peerHost, peerPort, false), executor);
484     }
485 
486     SSLEngine newEngine0(ByteBufAllocator alloc, String peerHost, int peerPort, boolean jdkCompatibilityMode) {
487         return new ReferenceCountedOpenSslEngine(this, alloc, peerHost, peerPort, jdkCompatibilityMode, true);
488     }
489 
490     /**
491      * Returns a new server-side {@link SSLEngine} with the current configuration.
492      */
493     @Override
494     public final SSLEngine newEngine(ByteBufAllocator alloc) {
495         return newEngine(alloc, null, -1);
496     }
497 
498     /**
499      * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}.
500      * Be aware that it is freed as soon as the {@link #finalize()}  method is called.
501      * At this point {@code 0} will be returned.
502      *
503      * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it!
504      */
505     @Deprecated
506     public final long context() {
507         return sslCtxPointer();
508     }
509 
510     /**
511      * Returns the stats of this context.
512      *
513      * @deprecated use {@link #sessionContext#stats()}
514      */
515     @Deprecated
516     public final OpenSslSessionStats stats() {
517         return sessionContext().stats();
518     }
519 
520     /**
521      * {@deprecated Renegotiation is not supported}
522      * Specify if remote initiated renegotiation is supported or not. If not supported and the remote side tries
523      * to initiate a renegotiation a {@link SSLHandshakeException} will be thrown during decoding.
524      */
525     @Deprecated
526     public void setRejectRemoteInitiatedRenegotiation(boolean rejectRemoteInitiatedRenegotiation) {
527         if (!rejectRemoteInitiatedRenegotiation) {
528             throw new UnsupportedOperationException("Renegotiation is not supported");
529         }
530     }
531 
532     /**
533      * {@deprecated Renegotiation is not supported}
534      * @return {@code true} because renegotiation is not supported.
535      */
536     @Deprecated
537     public boolean getRejectRemoteInitiatedRenegotiation() {
538         return true;
539     }
540 
541     /**
542      * Set the size of the buffer used by the BIO for non-application based writes
543      * (e.g. handshake, renegotiation, etc...).
544      */
545     public void setBioNonApplicationBufferSize(int bioNonApplicationBufferSize) {
546         this.bioNonApplicationBufferSize =
547                 checkPositiveOrZero(bioNonApplicationBufferSize, "bioNonApplicationBufferSize");
548     }
549 
550     /**
551      * Returns the size of the buffer used by the BIO for non-application based writes
552      */
553     public int getBioNonApplicationBufferSize() {
554         return bioNonApplicationBufferSize;
555     }
556 
557     /**
558      * Sets the SSL session ticket keys of this context.
559      *
560      * @deprecated use {@link OpenSslSessionContext#setTicketKeys(byte[])}
561      */
562     @Deprecated
563     public final void setTicketKeys(byte[] keys) {
564         sessionContext().setTicketKeys(keys);
565     }
566 
567     @Override
568     public abstract OpenSslSessionContext sessionContext();
569 
570     /**
571      * Returns the pointer to the {@code SSL_CTX} object for this {@link ReferenceCountedOpenSslContext}.
572      * Be aware that it is freed as soon as the {@link #release()} method is called.
573      * At this point {@code 0} will be returned.
574      *
575      * @deprecated this method is considered unsafe as the returned pointer may be released later. Dont use it!
576      */
577     @Deprecated
578     public final long sslCtxPointer() {
579         Lock readerLock = ctxLock.readLock();
580         readerLock.lock();
581         try {
582             return SSLContext.getSslCtx(ctx);
583         } finally {
584             readerLock.unlock();
585         }
586     }
587 
588     /**
589      * Set the {@link OpenSslPrivateKeyMethod} to use. This allows to offload private-key operations
590      * if needed.
591      *
592      * This method is currently only supported when {@code BoringSSL} is used.
593      *
594      * @param        method method to use.
595      * @deprecated   use {@link SslContextBuilder#option(SslContextOption, Object)} with
596      *              {@link OpenSslContextOption#PRIVATE_KEY_METHOD}.
597      */
598     @Deprecated
599     @UnstableApi
600     public final void setPrivateKeyMethod(OpenSslPrivateKeyMethod method) {
601         checkNotNull(method, "method");
602         Lock writerLock = ctxLock.writeLock();
603         writerLock.lock();
604         try {
605             SSLContext.setPrivateKeyMethod(ctx, new PrivateKeyMethod(engineMap, method));
606         } finally {
607             writerLock.unlock();
608         }
609     }
610 
611     /**
612      * @deprecated   use {@link SslContextBuilder#option(SslContextOption, Object)} with
613      *              {@link OpenSslContextOption#USE_TASKS}.
614      */
615     @Deprecated
616     public final void setUseTasks(boolean useTasks) {
617         Lock writerLock = ctxLock.writeLock();
618         writerLock.lock();
619         try {
620             SSLContext.setUseTasks(ctx, useTasks);
621         } finally {
622             writerLock.unlock();
623         }
624     }
625 
626     // IMPORTANT: This method must only be called from either the constructor or the finalizer as a user MUST never
627     //            get access to an OpenSslSessionContext after this method was called to prevent the user from
628     //            producing a segfault.
629     private void destroy() {
630         Lock writerLock = ctxLock.writeLock();
631         writerLock.lock();
632         try {
633             if (ctx != 0) {
634                 if (enableOcsp) {
635                     SSLContext.disableOcsp(ctx);
636                 }
637 
638                 SSLContext.free(ctx);
639                 ctx = 0;
640 
641                 OpenSslSessionContext context = sessionContext();
642                 if (context != null) {
643                     context.destroy();
644                 }
645             }
646         } finally {
647             writerLock.unlock();
648         }
649     }
650 
651     protected static X509Certificate[] certificates(byte[][] chain) {
652         X509Certificate[] peerCerts = new X509Certificate[chain.length];
653         for (int i = 0; i < peerCerts.length; i++) {
654             peerCerts[i] = new LazyX509Certificate(chain[i]);
655         }
656         return peerCerts;
657     }
658 
659     protected static X509TrustManager chooseTrustManager(TrustManager[] managers) {
660         for (TrustManager m : managers) {
661             if (m instanceof X509TrustManager) {
662                 X509TrustManager tm = (X509TrustManager) m;
663                 if (PlatformDependent.javaVersion() >= 7) {
664                     tm = OpenSslX509TrustManagerWrapper.wrapIfNeeded((X509TrustManager) m);
665                     if (useExtendedTrustManager(tm)) {
666                         // Wrap the TrustManager to provide a better exception message for users to debug hostname
667                         // validation failures.
668                         tm = new EnhancingX509ExtendedTrustManager(tm);
669                     }
670                 }
671                 return tm;
672             }
673         }
674         throw new IllegalStateException("no X509TrustManager found");
675     }
676 
677     protected static X509KeyManager chooseX509KeyManager(KeyManager[] kms) {
678         for (KeyManager km : kms) {
679             if (km instanceof X509KeyManager) {
680                 return (X509KeyManager) km;
681             }
682         }
683         throw new IllegalStateException("no X509KeyManager found");
684     }
685 
686     /**
687      * Translate a {@link ApplicationProtocolConfig} object to a
688      * {@link OpenSslApplicationProtocolNegotiator} object.
689      *
690      * @param config The configuration which defines the translation
691      * @return The results of the translation
692      */
693     @SuppressWarnings("deprecation")
694     static OpenSslApplicationProtocolNegotiator toNegotiator(ApplicationProtocolConfig config) {
695         if (config == null) {
696             return NONE_PROTOCOL_NEGOTIATOR;
697         }
698 
699         switch (config.protocol()) {
700             case NONE:
701                 return NONE_PROTOCOL_NEGOTIATOR;
702             case ALPN:
703             case NPN:
704             case NPN_AND_ALPN:
705                 switch (config.selectedListenerFailureBehavior()) {
706                     case CHOOSE_MY_LAST_PROTOCOL:
707                     case ACCEPT:
708                         switch (config.selectorFailureBehavior()) {
709                             case CHOOSE_MY_LAST_PROTOCOL:
710                             case NO_ADVERTISE:
711                                 return new OpenSslDefaultApplicationProtocolNegotiator(
712                                         config);
713                             default:
714                                 throw new UnsupportedOperationException(
715                                         new StringBuilder("OpenSSL provider does not support ")
716                                                 .append(config.selectorFailureBehavior())
717                                                 .append(" behavior").toString());
718                         }
719                     default:
720                         throw new UnsupportedOperationException(
721                                 new StringBuilder("OpenSSL provider does not support ")
722                                         .append(config.selectedListenerFailureBehavior())
723                                         .append(" behavior").toString());
724                 }
725             default:
726                 throw new Error();
727         }
728     }
729 
730     @SuppressJava6Requirement(reason = "Guarded by java version check")
731     static boolean useExtendedTrustManager(X509TrustManager trustManager) {
732         return PlatformDependent.javaVersion() >= 7 && trustManager instanceof X509ExtendedTrustManager;
733     }
734 
735     @Override
736     public final int refCnt() {
737         return refCnt.refCnt();
738     }
739 
740     @Override
741     public final ReferenceCounted retain() {
742         refCnt.retain();
743         return this;
744     }
745 
746     @Override
747     public final ReferenceCounted retain(int increment) {
748         refCnt.retain(increment);
749         return this;
750     }
751 
752     @Override
753     public final ReferenceCounted touch() {
754         refCnt.touch();
755         return this;
756     }
757 
758     @Override
759     public final ReferenceCounted touch(Object hint) {
760         refCnt.touch(hint);
761         return this;
762     }
763 
764     @Override
765     public final boolean release() {
766         return refCnt.release();
767     }
768 
769     @Override
770     public final boolean release(int decrement) {
771         return refCnt.release(decrement);
772     }
773 
774     abstract static class AbstractCertificateVerifier extends CertificateVerifier {
775         private final OpenSslEngineMap engineMap;
776 
777         AbstractCertificateVerifier(OpenSslEngineMap engineMap) {
778             this.engineMap = engineMap;
779         }
780 
781         @Override
782         public final int verify(long ssl, byte[][] chain, String auth) {
783             final ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
784             if (engine == null) {
785                 // May be null if it was destroyed in the meantime.
786                 return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
787             }
788             X509Certificate[] peerCerts = certificates(chain);
789             try {
790                 verify(engine, peerCerts, auth);
791                 return CertificateVerifier.X509_V_OK;
792             } catch (Throwable cause) {
793                 logger.debug("verification of certificate failed", cause);
794                 engine.initHandshakeException(cause);
795 
796                 // Try to extract the correct error code that should be used.
797                 if (cause instanceof OpenSslCertificateException) {
798                     // This will never return a negative error code as its validated when constructing the
799                     // OpenSslCertificateException.
800                     return ((OpenSslCertificateException) cause).errorCode();
801                 }
802                 if (cause instanceof CertificateExpiredException) {
803                     return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
804                 }
805                 if (cause instanceof CertificateNotYetValidException) {
806                     return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
807                 }
808                 if (PlatformDependent.javaVersion() >= 7) {
809                     return translateToError(cause);
810                 }
811 
812                 // Could not detect a specific error code to use, so fallback to a default code.
813                 return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
814             }
815         }
816 
817         @SuppressJava6Requirement(reason = "Usage guarded by java version check")
818         private static int translateToError(Throwable cause) {
819             if (cause instanceof CertificateRevokedException) {
820                 return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
821             }
822 
823             // The X509TrustManagerImpl uses a Validator which wraps a CertPathValidatorException into
824             // an CertificateException. So we need to handle the wrapped CertPathValidatorException to be
825             // able to send the correct alert.
826             Throwable wrapped = cause.getCause();
827             while (wrapped != null) {
828                 if (wrapped instanceof CertPathValidatorException) {
829                     CertPathValidatorException ex = (CertPathValidatorException) wrapped;
830                     CertPathValidatorException.Reason reason = ex.getReason();
831                     if (reason == CertPathValidatorException.BasicReason.EXPIRED) {
832                         return CertificateVerifier.X509_V_ERR_CERT_HAS_EXPIRED;
833                     }
834                     if (reason == CertPathValidatorException.BasicReason.NOT_YET_VALID) {
835                         return CertificateVerifier.X509_V_ERR_CERT_NOT_YET_VALID;
836                     }
837                     if (reason == CertPathValidatorException.BasicReason.REVOKED) {
838                         return CertificateVerifier.X509_V_ERR_CERT_REVOKED;
839                     }
840                 }
841                 wrapped = wrapped.getCause();
842             }
843             return CertificateVerifier.X509_V_ERR_UNSPECIFIED;
844         }
845 
846         abstract void verify(ReferenceCountedOpenSslEngine engine, X509Certificate[] peerCerts,
847                              String auth) throws Exception;
848     }
849 
850     private static final class DefaultOpenSslEngineMap implements OpenSslEngineMap {
851         private final Map<Long, ReferenceCountedOpenSslEngine> engines = PlatformDependent.newConcurrentHashMap();
852 
853         @Override
854         public ReferenceCountedOpenSslEngine remove(long ssl) {
855             return engines.remove(ssl);
856         }
857 
858         @Override
859         public void add(ReferenceCountedOpenSslEngine engine) {
860             engines.put(engine.sslPointer(), engine);
861         }
862 
863         @Override
864         public ReferenceCountedOpenSslEngine get(long ssl) {
865             return engines.get(ssl);
866         }
867     }
868 
869     static void setKeyMaterial(long ctx, X509Certificate[] keyCertChain, PrivateKey key, String keyPassword)
870             throws SSLException {
871          /* Load the certificate file and private key. */
872         long keyBio = 0;
873         long keyCertChainBio = 0;
874         long keyCertChainBio2 = 0;
875         PemEncoded encoded = null;
876         try {
877             // Only encode one time
878             encoded = PemX509Certificate.toPEM(ByteBufAllocator.DEFAULT, true, keyCertChain);
879             keyCertChainBio = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
880             keyCertChainBio2 = toBIO(ByteBufAllocator.DEFAULT, encoded.retain());
881 
882             if (key != null) {
883                 keyBio = toBIO(ByteBufAllocator.DEFAULT, key);
884             }
885 
886             SSLContext.setCertificateBio(
887                     ctx, keyCertChainBio, keyBio,
888                     keyPassword == null ? StringUtil.EMPTY_STRING : keyPassword);
889             // We may have more then one cert in the chain so add all of them now.
890             SSLContext.setCertificateChainBio(ctx, keyCertChainBio2, true);
891         } catch (SSLException e) {
892             throw e;
893         } catch (Exception e) {
894             throw new SSLException("failed to set certificate and key", e);
895         } finally {
896             freeBio(keyBio);
897             freeBio(keyCertChainBio);
898             freeBio(keyCertChainBio2);
899             if (encoded != null) {
900                 encoded.release();
901             }
902         }
903     }
904 
905     static void freeBio(long bio) {
906         if (bio != 0) {
907             SSL.freeBIO(bio);
908         }
909     }
910 
911     /**
912      * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a>
913      * or {@code 0} if the {@code key} is {@code null}. The BIO contains the content of the {@code key}.
914      */
915     static long toBIO(ByteBufAllocator allocator, PrivateKey key) throws Exception {
916         if (key == null) {
917             return 0;
918         }
919 
920         PemEncoded pem = PemPrivateKey.toPEM(allocator, true, key);
921         try {
922             return toBIO(allocator, pem.retain());
923         } finally {
924             pem.release();
925         }
926     }
927 
928     /**
929      * Return the pointer to a <a href="https://www.openssl.org/docs/crypto/BIO_get_mem_ptr.html">in-memory BIO</a>
930      * or {@code 0} if the {@code certChain} is {@code null}. The BIO contains the content of the {@code certChain}.
931      */
932     static long toBIO(ByteBufAllocator allocator, X509Certificate... certChain) throws Exception {
933         if (certChain == null) {
934             return 0;
935         }
936 
937         checkNonEmpty(certChain, "certChain");
938 
939         PemEncoded pem = PemX509Certificate.toPEM(allocator, true, certChain);
940         try {
941             return toBIO(allocator, pem.retain());
942         } finally {
943             pem.release();
944         }
945     }
946 
947     static long toBIO(ByteBufAllocator allocator, PemEncoded pem) throws Exception {
948         try {
949             // We can turn direct buffers straight into BIOs. No need to
950             // make a yet another copy.
951             ByteBuf content = pem.content();
952 
953             if (content.isDirect()) {
954                 return newBIO(content.retainedSlice());
955             }
956 
957             ByteBuf buffer = allocator.directBuffer(content.readableBytes());
958             try {
959                 buffer.writeBytes(content, content.readerIndex(), content.readableBytes());
960                 return newBIO(buffer.retainedSlice());
961             } finally {
962                 try {
963                     // If the contents of the ByteBuf is sensitive (e.g. a PrivateKey) we
964                     // need to zero out the bytes of the copy before we're releasing it.
965                     if (pem.isSensitive()) {
966                         SslUtils.zeroout(buffer);
967                     }
968                 } finally {
969                     buffer.release();
970                 }
971             }
972         } finally {
973             pem.release();
974         }
975     }
976 
977     private static long newBIO(ByteBuf buffer) throws Exception {
978         try {
979             long bio = SSL.newMemBIO();
980             int readable = buffer.readableBytes();
981             if (SSL.bioWrite(bio, OpenSsl.memoryAddress(buffer) + buffer.readerIndex(), readable) != readable) {
982                 SSL.freeBIO(bio);
983                 throw new IllegalStateException("Could not write data to memory BIO");
984             }
985             return bio;
986         } finally {
987             buffer.release();
988         }
989     }
990 
991     /**
992      * Returns the {@link OpenSslKeyMaterialProvider} that should be used for OpenSSL. Depending on the given
993      * {@link KeyManagerFactory} this may cache the {@link OpenSslKeyMaterial} for better performance if it can
994      * ensure that the same material is always returned for the same alias.
995      */
996     static OpenSslKeyMaterialProvider providerFor(KeyManagerFactory factory, String password) {
997         if (factory instanceof OpenSslX509KeyManagerFactory) {
998             return ((OpenSslX509KeyManagerFactory) factory).newProvider();
999         }
1000 
1001         if (factory instanceof OpenSslCachingX509KeyManagerFactory) {
1002             // The user explicit used OpenSslCachingX509KeyManagerFactory which signals us that its fine to cache.
1003             return ((OpenSslCachingX509KeyManagerFactory) factory).newProvider(password);
1004         }
1005         // We can not be sure if the material may change at runtime so we will not cache it.
1006         return new OpenSslKeyMaterialProvider(chooseX509KeyManager(factory.getKeyManagers()), password);
1007     }
1008 
1009     private static ReferenceCountedOpenSslEngine retrieveEngine(OpenSslEngineMap engineMap, long ssl)
1010             throws SSLException {
1011         ReferenceCountedOpenSslEngine engine = engineMap.get(ssl);
1012         if (engine == null) {
1013             throw new SSLException("Could not find a " +
1014                     StringUtil.simpleClassName(ReferenceCountedOpenSslEngine.class) + " for sslPointer " + ssl);
1015         }
1016         return engine;
1017     }
1018 
1019     private static final class PrivateKeyMethod implements SSLPrivateKeyMethod {
1020 
1021         private final OpenSslEngineMap engineMap;
1022         private final OpenSslPrivateKeyMethod keyMethod;
1023         PrivateKeyMethod(OpenSslEngineMap engineMap, OpenSslPrivateKeyMethod keyMethod) {
1024             this.engineMap = engineMap;
1025             this.keyMethod = keyMethod;
1026         }
1027 
1028         @Override
1029         public byte[] sign(long ssl, int signatureAlgorithm, byte[] digest) throws Exception {
1030             ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
1031             try {
1032                 return verifyResult(keyMethod.sign(engine, signatureAlgorithm, digest));
1033             } catch (Exception e) {
1034                 engine.initHandshakeException(e);
1035                 throw e;
1036             }
1037         }
1038 
1039         @Override
1040         public byte[] decrypt(long ssl, byte[] input) throws Exception {
1041             ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
1042             try {
1043                 return verifyResult(keyMethod.decrypt(engine, input));
1044             } catch (Exception e) {
1045                 engine.initHandshakeException(e);
1046                 throw e;
1047             }
1048         }
1049     }
1050 
1051     private static final class AsyncPrivateKeyMethod implements AsyncSSLPrivateKeyMethod {
1052 
1053         private final OpenSslEngineMap engineMap;
1054         private final OpenSslAsyncPrivateKeyMethod keyMethod;
1055 
1056         AsyncPrivateKeyMethod(OpenSslEngineMap engineMap, OpenSslAsyncPrivateKeyMethod keyMethod) {
1057             this.engineMap = engineMap;
1058             this.keyMethod = keyMethod;
1059         }
1060 
1061         @Override
1062         public void sign(long ssl, int signatureAlgorithm, byte[] bytes, ResultCallback<byte[]> resultCallback) {
1063             try {
1064                 ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
1065                 keyMethod.sign(engine, signatureAlgorithm, bytes)
1066                         .addListener(new ResultCallbackListener(engine, ssl, resultCallback));
1067             } catch (SSLException e) {
1068                 resultCallback.onError(ssl, e);
1069             }
1070         }
1071 
1072         @Override
1073         public void decrypt(long ssl, byte[] bytes, ResultCallback<byte[]> resultCallback) {
1074             try {
1075                 ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
1076                 keyMethod.decrypt(engine, bytes)
1077                         .addListener(new ResultCallbackListener(engine, ssl, resultCallback));
1078             } catch (SSLException e) {
1079                 resultCallback.onError(ssl, e);
1080             }
1081         }
1082 
1083         private static final class ResultCallbackListener implements FutureListener<byte[]> {
1084             private final ReferenceCountedOpenSslEngine engine;
1085             private final long ssl;
1086             private final ResultCallback<byte[]> resultCallback;
1087 
1088             ResultCallbackListener(ReferenceCountedOpenSslEngine engine, long ssl,
1089                                    ResultCallback<byte[]> resultCallback) {
1090                 this.engine = engine;
1091                 this.ssl = ssl;
1092                 this.resultCallback = resultCallback;
1093             }
1094 
1095             @Override
1096             public void operationComplete(Future<byte[]> future) {
1097                 Throwable cause = future.cause();
1098                 if (cause == null) {
1099                     try {
1100                         byte[] result = verifyResult(future.getNow());
1101                         resultCallback.onSuccess(ssl, result);
1102                         return;
1103                     } catch (SignatureException e) {
1104                         cause = e;
1105                         engine.initHandshakeException(e);
1106                     }
1107                 }
1108                 resultCallback.onError(ssl, cause);
1109             }
1110         }
1111     }
1112 
1113     private static byte[] verifyResult(byte[] result) throws SignatureException {
1114         if (result == null) {
1115             throw new SignatureException();
1116         }
1117         return result;
1118     }
1119 
1120     private static final class CompressionAlgorithm implements CertificateCompressionAlgo {
1121         private final OpenSslEngineMap engineMap;
1122         private final OpenSslCertificateCompressionAlgorithm compressionAlgorithm;
1123 
1124         CompressionAlgorithm(OpenSslEngineMap engineMap, OpenSslCertificateCompressionAlgorithm compressionAlgorithm) {
1125             this.engineMap = engineMap;
1126             this.compressionAlgorithm = compressionAlgorithm;
1127         }
1128 
1129         @Override
1130         public byte[] compress(long ssl, byte[] bytes) throws Exception {
1131             ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
1132             return compressionAlgorithm.compress(engine, bytes);
1133         }
1134 
1135         @Override
1136         public byte[] decompress(long ssl, int len, byte[] bytes) throws Exception {
1137             ReferenceCountedOpenSslEngine engine = retrieveEngine(engineMap, ssl);
1138             return compressionAlgorithm.decompress(engine, len, bytes);
1139         }
1140 
1141         @Override
1142         public int algorithmId() {
1143             return compressionAlgorithm.algorithmId();
1144         }
1145     }
1146 }