View Javadoc
1   /*
2    * Copyright 2014 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  
17  package io.netty.handler.ssl;
18  
19  import io.netty.buffer.ByteBuf;
20  import io.netty.buffer.ByteBufAllocator;
21  import io.netty.buffer.ByteBufInputStream;
22  import io.netty.channel.ChannelInitializer;
23  import io.netty.channel.ChannelPipeline;
24  import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
25  import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
26  import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
27  import io.netty.handler.ssl.util.BouncyCastleUtil;
28  import io.netty.util.AttributeMap;
29  import io.netty.util.DefaultAttributeMap;
30  import io.netty.util.concurrent.ImmediateExecutor;
31  import io.netty.util.internal.EmptyArrays;
32  import io.netty.util.internal.SystemPropertyUtil;
33  import io.netty.util.internal.logging.InternalLogger;
34  import io.netty.util.internal.logging.InternalLoggerFactory;
35  
36  import java.io.BufferedInputStream;
37  import java.io.File;
38  import java.io.IOException;
39  import java.io.InputStream;
40  import java.security.AlgorithmParameters;
41  import java.security.InvalidAlgorithmParameterException;
42  import java.security.InvalidKeyException;
43  import java.security.KeyException;
44  import java.security.KeyFactory;
45  import java.security.KeyStore;
46  import java.security.KeyStoreException;
47  import java.security.NoSuchAlgorithmException;
48  import java.security.PrivateKey;
49  import java.security.Provider;
50  import java.security.SecureRandom;
51  import java.security.UnrecoverableKeyException;
52  import java.security.cert.CertificateException;
53  import java.security.cert.CertificateFactory;
54  import java.security.cert.X509Certificate;
55  import java.security.spec.InvalidKeySpecException;
56  import java.security.spec.PKCS8EncodedKeySpec;
57  import java.util.Collections;
58  import java.util.List;
59  import java.util.Map;
60  import java.util.concurrent.Executor;
61  import javax.crypto.Cipher;
62  import javax.crypto.EncryptedPrivateKeyInfo;
63  import javax.crypto.NoSuchPaddingException;
64  import javax.crypto.SecretKey;
65  import javax.crypto.SecretKeyFactory;
66  import javax.crypto.spec.PBEKeySpec;
67  import javax.net.ssl.KeyManager;
68  import javax.net.ssl.KeyManagerFactory;
69  import javax.net.ssl.SNIServerName;
70  import javax.net.ssl.SSLContext;
71  import javax.net.ssl.SSLEngine;
72  import javax.net.ssl.SSLException;
73  import javax.net.ssl.SSLSessionContext;
74  import javax.net.ssl.TrustManager;
75  import javax.net.ssl.TrustManagerFactory;
76  
77  /**
78   * A secure socket protocol implementation which acts as a factory for {@link SSLEngine} and {@link SslHandler}.
79   * Internally, it is implemented via JDK's {@link SSLContext} or OpenSSL's {@code SSL_CTX}.
80   *
81   * <h3>Making your server support SSL/TLS</h3>
82   * <pre>
83   * // In your {@link ChannelInitializer}:
84   * {@link ChannelPipeline} p = channel.pipeline();
85   * {@link SslContext} sslCtx = {@link SslContextBuilder#forServer(File, File) SslContextBuilder.forServer(...)}.build();
86   * p.addLast("ssl", {@link #newHandler(ByteBufAllocator) sslCtx.newHandler(channel.alloc())});
87   * ...
88   * </pre>
89   *
90   * <h3>Making your client support SSL/TLS</h3>
91   * <pre>
92   * // In your {@link ChannelInitializer}:
93   * {@link ChannelPipeline} p = channel.pipeline();
94   * {@link SslContext} sslCtx = {@link SslContextBuilder#forClient() SslContextBuilder.forClient()}.build();
95   * p.addLast("ssl", {@link #newHandler(ByteBufAllocator, String, int) sslCtx.newHandler(channel.alloc(), host, port)});
96   * ...
97   * </pre>
98   */
99  public abstract class SslContext {
100     private static final InternalLogger logger = InternalLoggerFactory.getInstance(SslContext.class);
101 
102     private static final String DEFAULT_ENDPOINT_VERIFICATION_ALGORITHM_PROPERTY =
103             "io.netty.handler.ssl.defaultEndpointVerificationAlgorithm";
104 
105     /**
106      * Endpoint verification is enabled by default from Netty 4.2 onward, but it wasn't in Netty 4.1 and earlier.
107      * The {@value #DEFAULT_ENDPOINT_VERIFICATION_ALGORITHM_PROPERTY} can be set to one of the following
108      * values to control this behavior:
109      * <ul>
110      *     <li>{@code "HTTPS"} — verify subject by DNS hostnames; this is the Netty 4.2 default.</li>
111      *     <li>{@code "LDAP"} — verify subject by LDAP identity.</li>
112      *     <li>{@code "NONE"} — don't enable endpoint verification by default; this is the Netty 4.1 behavior.</li>
113      * </ul>
114      */
115     protected static final String defaultEndpointVerificationAlgorithm;
116     static final String ALIAS = "key";
117 
118     static final CertificateFactory X509_CERT_FACTORY;
119     static {
120         try {
121             X509_CERT_FACTORY = CertificateFactory.getInstance("X.509");
122         } catch (CertificateException e) {
123             throw new IllegalStateException("unable to instance X.509 CertificateFactory", e);
124         }
125 
126         String defaultEndpointVerification = SystemPropertyUtil.get(DEFAULT_ENDPOINT_VERIFICATION_ALGORITHM_PROPERTY);
127         if ("LDAP".equalsIgnoreCase(defaultEndpointVerification)) {
128             defaultEndpointVerificationAlgorithm = "LDAP";
129         } else if ("NONE".equalsIgnoreCase(defaultEndpointVerification)) {
130             logger.info("Default SSL endpoint verification has been disabled:  -D{}=\"{}\"",
131                     DEFAULT_ENDPOINT_VERIFICATION_ALGORITHM_PROPERTY, defaultEndpointVerification);
132             defaultEndpointVerificationAlgorithm = null;
133         } else {
134             if (defaultEndpointVerification != null && !"HTTPS".equalsIgnoreCase(defaultEndpointVerification)) {
135                 logger.warn("Unknown default SSL endpoint verification algorithm: -D{}=\"{}\", " +
136                                 "will use \"HTTPS\" instead.",
137                         DEFAULT_ENDPOINT_VERIFICATION_ALGORITHM_PROPERTY, defaultEndpointVerification);
138             }
139             defaultEndpointVerificationAlgorithm = "HTTPS";
140         }
141     }
142 
143     private final boolean startTls;
144     private final AttributeMap attributes = new DefaultAttributeMap();
145     final ResumptionController resumptionController;
146     private static final String OID_PKCS5_PBES2 = "1.2.840.113549.1.5.13";
147     private static final String PBES2 = "PBES2";
148 
149     /**
150      * Returns the default server-side implementation provider currently in use.
151      *
152      * @return {@link SslProvider#OPENSSL} if OpenSSL is available. {@link SslProvider#JDK} otherwise.
153      */
154     public static SslProvider defaultServerProvider() {
155         return defaultProvider();
156     }
157 
158     /**
159      * Returns the default client-side implementation provider currently in use.
160      *
161      * @return {@link SslProvider#OPENSSL} if OpenSSL is available. {@link SslProvider#JDK} otherwise.
162      */
163     public static SslProvider defaultClientProvider() {
164         return defaultProvider();
165     }
166 
167     private static SslProvider defaultProvider() {
168         if (OpenSsl.isAvailable()) {
169             return SslProvider.OPENSSL;
170         } else {
171             return SslProvider.JDK;
172         }
173     }
174 
175     /**
176      * Creates a new server-side {@link SslContext}.
177      *
178      * @param certChainFile an X.509 certificate chain file in PEM format
179      * @param keyFile a PKCS#8 private key file in PEM format
180      * @return a new server-side {@link SslContext}
181      * @deprecated Replaced by {@link SslContextBuilder}
182      */
183     @Deprecated
184     public static SslContext newServerContext(File certChainFile, File keyFile) throws SSLException {
185         return newServerContext(certChainFile, keyFile, null);
186     }
187 
188     /**
189      * Creates a new server-side {@link SslContext}.
190      *
191      * @param certChainFile an X.509 certificate chain file in PEM format
192      * @param keyFile a PKCS#8 private key file in PEM format
193      * @param keyPassword the password of the {@code keyFile}.
194      *                    {@code null} if it's not password-protected.
195      * @return a new server-side {@link SslContext}
196      * @deprecated Replaced by {@link SslContextBuilder}
197      */
198     @Deprecated
199     public static SslContext newServerContext(
200             File certChainFile, File keyFile, String keyPassword) throws SSLException {
201         return newServerContext(null, certChainFile, keyFile, keyPassword);
202     }
203 
204     /**
205      * Creates a new server-side {@link SslContext}.
206      *
207      * @param certChainFile an X.509 certificate chain file in PEM format
208      * @param keyFile a PKCS#8 private key file in PEM format
209      * @param keyPassword the password of the {@code keyFile}.
210      *                    {@code null} if it's not password-protected.
211      * @param ciphers the cipher suites to enable, in the order of preference.
212      *                {@code null} to use the default cipher suites.
213      * @param nextProtocols the application layer protocols to accept, in the order of preference.
214      *                      {@code null} to disable TLS NPN/ALPN extension.
215      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
216      *                         {@code 0} to use the default value.
217      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
218      *                       {@code 0} to use the default value.
219      * @return a new server-side {@link SslContext}
220      * @deprecated Replaced by {@link SslContextBuilder}
221      */
222     @Deprecated
223     public static SslContext newServerContext(
224             File certChainFile, File keyFile, String keyPassword,
225             Iterable<String> ciphers, Iterable<String> nextProtocols,
226             long sessionCacheSize, long sessionTimeout) throws SSLException {
227 
228         return newServerContext(
229                 null, certChainFile, keyFile, keyPassword,
230                 ciphers, nextProtocols, sessionCacheSize, sessionTimeout);
231     }
232 
233     /**
234      * Creates a new server-side {@link SslContext}.
235      *
236      * @param certChainFile an X.509 certificate chain file in PEM format
237      * @param keyFile a PKCS#8 private key file in PEM format
238      * @param keyPassword the password of the {@code keyFile}.
239      *                    {@code null} if it's not password-protected.
240      * @param ciphers the cipher suites to enable, in the order of preference.
241      *                {@code null} to use the default cipher suites.
242      * @param cipherFilter a filter to apply over the supplied list of ciphers
243      * @param apn Provides a means to configure parameters related to application protocol negotiation.
244      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
245      *                         {@code 0} to use the default value.
246      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
247      *                       {@code 0} to use the default value.
248      * @return a new server-side {@link SslContext}
249      * @deprecated Replaced by {@link SslContextBuilder}
250      */
251     @Deprecated
252     public static SslContext newServerContext(
253             File certChainFile, File keyFile, String keyPassword,
254             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
255             long sessionCacheSize, long sessionTimeout) throws SSLException {
256         return newServerContext(
257                 null, certChainFile, keyFile, keyPassword,
258                 ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
259     }
260 
261     /**
262      * Creates a new server-side {@link SslContext}.
263      *
264      * @param provider the {@link SslContext} implementation to use.
265      *                 {@code null} to use the current default one.
266      * @param certChainFile an X.509 certificate chain file in PEM format
267      * @param keyFile a PKCS#8 private key file in PEM format
268      * @return a new server-side {@link SslContext}
269      * @deprecated Replaced by {@link SslContextBuilder}
270      */
271     @Deprecated
272     public static SslContext newServerContext(
273             SslProvider provider, File certChainFile, File keyFile) throws SSLException {
274         return newServerContext(provider, certChainFile, keyFile, null);
275     }
276 
277     /**
278      * Creates a new server-side {@link SslContext}.
279      *
280      * @param provider the {@link SslContext} implementation to use.
281      *                 {@code null} to use the current default one.
282      * @param certChainFile an X.509 certificate chain file in PEM format
283      * @param keyFile a PKCS#8 private key file in PEM format
284      * @param keyPassword the password of the {@code keyFile}.
285      *                    {@code null} if it's not password-protected.
286      * @return a new server-side {@link SslContext}
287      * @deprecated Replaced by {@link SslContextBuilder}
288      */
289     @Deprecated
290     public static SslContext newServerContext(
291             SslProvider provider, File certChainFile, File keyFile, String keyPassword) throws SSLException {
292         return newServerContext(provider, certChainFile, keyFile, keyPassword, null, IdentityCipherSuiteFilter.INSTANCE,
293                                 null, 0, 0);
294     }
295 
296     /**
297      * Creates a new server-side {@link SslContext}.
298      *
299      * @param provider the {@link SslContext} implementation to use.
300      *                 {@code null} to use the current default one.
301      * @param certChainFile an X.509 certificate chain file in PEM format
302      * @param keyFile a PKCS#8 private key file in PEM format
303      * @param keyPassword the password of the {@code keyFile}.
304      *                    {@code null} if it's not password-protected.
305      * @param ciphers the cipher suites to enable, in the order of preference.
306      *                {@code null} to use the default cipher suites.
307      * @param nextProtocols the application layer protocols to accept, in the order of preference.
308      *                      {@code null} to disable TLS NPN/ALPN extension.
309      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
310      *                         {@code 0} to use the default value.
311      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
312      *                       {@code 0} to use the default value.
313      * @return a new server-side {@link SslContext}
314      * @deprecated Replaced by {@link SslContextBuilder}
315      */
316     @Deprecated
317     public static SslContext newServerContext(
318             SslProvider provider,
319             File certChainFile, File keyFile, String keyPassword,
320             Iterable<String> ciphers, Iterable<String> nextProtocols,
321             long sessionCacheSize, long sessionTimeout) throws SSLException {
322         return newServerContext(provider, certChainFile, keyFile, keyPassword,
323                                 ciphers, IdentityCipherSuiteFilter.INSTANCE,
324                                 toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout);
325     }
326 
327     /**
328      * Creates a new server-side {@link SslContext}.
329      *
330      * @param provider the {@link SslContext} implementation to use.
331      *                 {@code null} to use the current default one.
332      * @param certChainFile an X.509 certificate chain file in PEM format
333      * @param keyFile a PKCS#8 private key file in PEM format
334      * @param keyPassword the password of the {@code keyFile}.
335      *                    {@code null} if it's not password-protected.
336      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
337      *                            that verifies the certificates sent from servers.
338      *                            {@code null} to use the default.
339      * @param ciphers the cipher suites to enable, in the order of preference.
340      *                {@code null} to use the default cipher suites.
341      * @param nextProtocols the application layer protocols to accept, in the order of preference.
342      *                      {@code null} to disable TLS NPN/ALPN extension.
343      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
344      *                         {@code 0} to use the default value.
345      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
346      *                       {@code 0} to use the default value.
347      * @return a new server-side {@link SslContext}
348      * @deprecated Replaced by {@link SslContextBuilder}
349      */
350     @Deprecated
351     public static SslContext newServerContext(
352             SslProvider provider,
353             File certChainFile, File keyFile, String keyPassword, TrustManagerFactory trustManagerFactory,
354             Iterable<String> ciphers, Iterable<String> nextProtocols,
355             long sessionCacheSize, long sessionTimeout) throws SSLException {
356 
357         return newServerContext(
358                 provider, null, trustManagerFactory, certChainFile, keyFile, keyPassword,
359                 null, ciphers, IdentityCipherSuiteFilter.INSTANCE,
360                 toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout);
361     }
362 
363     /**
364      * Creates a new server-side {@link SslContext}.
365      *
366      * @param provider the {@link SslContext} implementation to use.
367      *                 {@code null} to use the current default one.
368      * @param certChainFile an X.509 certificate chain file in PEM format
369      * @param keyFile a PKCS#8 private key file in PEM format
370      * @param keyPassword the password of the {@code keyFile}.
371      *                    {@code null} if it's not password-protected.
372      * @param ciphers the cipher suites to enable, in the order of preference.
373      *                {@code null} to use the default cipher suites.
374      * @param cipherFilter a filter to apply over the supplied list of ciphers
375      *                Only required if {@code provider} is {@link SslProvider#JDK}
376      * @param apn Provides a means to configure parameters related to application protocol negotiation.
377      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
378      *                         {@code 0} to use the default value.
379      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
380      *                       {@code 0} to use the default value.
381      * @return a new server-side {@link SslContext}
382      * @deprecated Replaced by {@link SslContextBuilder}
383      */
384     @Deprecated
385     public static SslContext newServerContext(SslProvider provider,
386             File certChainFile, File keyFile, String keyPassword,
387             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
388             long sessionCacheSize, long sessionTimeout) throws SSLException {
389         return newServerContext(provider, null, null, certChainFile, keyFile, keyPassword, null,
390                 ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout, KeyStore.getDefaultType());
391     }
392 
393     /**
394      * Creates a new server-side {@link SslContext}.
395      * @param provider the {@link SslContext} implementation to use.
396      *                 {@code null} to use the current default one.
397      * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
398      *                      This provides the certificate collection used for mutual authentication.
399      *                      {@code null} to use the system default
400      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
401      *                            that verifies the certificates sent from clients.
402      *                            {@code null} to use the default or the results of parsing
403      *                            {@code trustCertCollectionFile}.
404      *                            This parameter is ignored if {@code provider} is not {@link SslProvider#JDK}.
405      * @param keyCertChainFile an X.509 certificate chain file in PEM format
406      * @param keyFile a PKCS#8 private key file in PEM format
407      * @param keyPassword the password of the {@code keyFile}.
408      *                    {@code null} if it's not password-protected.
409      * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
410      *                          that is used to encrypt data being sent to clients.
411      *                          {@code null} to use the default or the results of parsing
412      *                          {@code keyCertChainFile} and {@code keyFile}.
413      *                          This parameter is ignored if {@code provider} is not {@link SslProvider#JDK}.
414      * @param ciphers the cipher suites to enable, in the order of preference.
415      *                {@code null} to use the default cipher suites.
416      * @param cipherFilter a filter to apply over the supplied list of ciphers
417      *                Only required if {@code provider} is {@link SslProvider#JDK}
418      * @param apn Provides a means to configure parameters related to application protocol negotiation.
419      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
420      *                         {@code 0} to use the default value.
421      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
422      *                       {@code 0} to use the default value.
423      * @return a new server-side {@link SslContext}
424      * @deprecated Replaced by {@link SslContextBuilder}
425      */
426     @Deprecated
427     public static SslContext newServerContext(
428             SslProvider provider,
429             File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
430             File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
431             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
432             long sessionCacheSize, long sessionTimeout) throws SSLException {
433         return newServerContext(provider, trustCertCollectionFile, trustManagerFactory, keyCertChainFile,
434                 keyFile, keyPassword, keyManagerFactory, ciphers, cipherFilter, apn,
435                 sessionCacheSize, sessionTimeout, KeyStore.getDefaultType());
436     }
437 
438     /**
439      * Creates a new server-side {@link SslContext}.
440      * @param provider the {@link SslContext} implementation to use.
441      *                 {@code null} to use the current default one.
442      * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
443      *                      This provides the certificate collection used for mutual authentication.
444      *                      {@code null} to use the system default
445      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
446      *                            that verifies the certificates sent from clients.
447      *                            {@code null} to use the default or the results of parsing
448      *                            {@code trustCertCollectionFile}.
449      *                            This parameter is ignored if {@code provider} is not {@link SslProvider#JDK}.
450      * @param keyCertChainFile an X.509 certificate chain file in PEM format
451      * @param keyFile a PKCS#8 private key file in PEM format
452      * @param keyPassword the password of the {@code keyFile}.
453      *                    {@code null} if it's not password-protected.
454      * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
455      *                          that is used to encrypt data being sent to clients.
456      *                          {@code null} to use the default or the results of parsing
457      *                          {@code keyCertChainFile} and {@code keyFile}.
458      *                          This parameter is ignored if {@code provider} is not {@link SslProvider#JDK}.
459      * @param ciphers the cipher suites to enable, in the order of preference.
460      *                {@code null} to use the default cipher suites.
461      * @param cipherFilter a filter to apply over the supplied list of ciphers
462      *                Only required if {@code provider} is {@link SslProvider#JDK}
463      * @param apn Provides a means to configure parameters related to application protocol negotiation.
464      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
465      *                         {@code 0} to use the default value.
466      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
467      *                       {@code 0} to use the default value.
468      * @param keyStore the keystore type that should  be used
469      * @return a new server-side {@link SslContext}
470      */
471     static SslContext newServerContext(
472             SslProvider provider,
473             File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
474             File keyCertChainFile, File keyFile, String keyPassword, KeyManagerFactory keyManagerFactory,
475             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
476             long sessionCacheSize, long sessionTimeout, String keyStore) throws SSLException {
477         try {
478             return newServerContextInternal(provider, null, toX509Certificates(trustCertCollectionFile),
479                                             trustManagerFactory, toX509Certificates(keyCertChainFile),
480                                             toPrivateKey(keyFile, keyPassword),
481                                             keyPassword, keyManagerFactory, ciphers, cipherFilter, apn,
482                                             sessionCacheSize, sessionTimeout, ClientAuth.NONE, null,
483                                             false, false, null, keyStore, null, null);
484         } catch (Exception e) {
485             if (e instanceof SSLException) {
486                 throw (SSLException) e;
487             }
488             throw new SSLException("failed to initialize the server-side SSL context", e);
489         }
490     }
491 
492     static SslContext newServerContextInternal(
493             SslProvider provider,
494             Provider sslContextProvider,
495             X509Certificate[] trustCertCollection, TrustManagerFactory trustManagerFactory,
496             X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
497             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
498             long sessionCacheSize, long sessionTimeout, ClientAuth clientAuth, String[] protocols, boolean startTls,
499             boolean enableOcsp, SecureRandom secureRandom, String keyStoreType,
500             Map.Entry<SslContextOption<?>, Object>[] ctxOptions,
501             List<OpenSslCredential> credentials)
502             throws SSLException {
503 
504         if (provider == null) {
505             provider = defaultServerProvider();
506         }
507 
508         ResumptionController resumptionController = new ResumptionController();
509 
510         switch (provider) {
511         case JDK:
512             if (enableOcsp) {
513                 throw new IllegalArgumentException("OCSP is not supported with this SslProvider: " + provider);
514             }
515             if (credentials != null && !credentials.isEmpty()) {
516                 throw new IllegalArgumentException(
517                         "OpenSslCredential is not supported with SslProvider.JDK. " +
518                                 "Use SslProvider.OPENSSL or SslProvider.OPENSSL_REFCNT instead.");
519             }
520             return new JdkSslServerContext(sslContextProvider,
521                     trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
522                     keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
523                     clientAuth, protocols, startTls, secureRandom, keyStoreType, resumptionController);
524         case OPENSSL:
525             verifyNullSslContextProvider(provider, sslContextProvider);
526             return new OpenSslServerContext(
527                     trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
528                     keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
529                     clientAuth, protocols, startTls, enableOcsp, keyStoreType, resumptionController, ctxOptions);
530         case OPENSSL_REFCNT:
531             verifyNullSslContextProvider(provider, sslContextProvider);
532             return new ReferenceCountedOpenSslServerContext(
533                     trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
534                     keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
535                     clientAuth, protocols, startTls, enableOcsp, keyStoreType, resumptionController, ctxOptions,
536                     credentials);
537         default:
538             throw new Error("Unexpected provider: " + provider);
539         }
540     }
541 
542     private static void verifyNullSslContextProvider(SslProvider provider, Provider sslContextProvider) {
543         if (sslContextProvider != null) {
544             throw new IllegalArgumentException("Java Security Provider unsupported for SslProvider: " + provider);
545         }
546     }
547 
548     /**
549      * Creates a new client-side {@link SslContext}.
550      *
551      * @return a new client-side {@link SslContext}
552      * @deprecated Replaced by {@link SslContextBuilder}
553      */
554     @Deprecated
555     public static SslContext newClientContext() throws SSLException {
556         return newClientContext(null, null, null);
557     }
558 
559     /**
560      * Creates a new client-side {@link SslContext}.
561      *
562      * @param certChainFile an X.509 certificate chain file in PEM format
563      *
564      * @return a new client-side {@link SslContext}
565      * @deprecated Replaced by {@link SslContextBuilder}
566      */
567     @Deprecated
568     public static SslContext newClientContext(File certChainFile) throws SSLException {
569         return newClientContext(null, certChainFile);
570     }
571 
572     /**
573      * Creates a new client-side {@link SslContext}.
574      *
575      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
576      *                            that verifies the certificates sent from servers.
577      *                            {@code null} to use the default.
578      *
579      * @return a new client-side {@link SslContext}
580      * @deprecated Replaced by {@link SslContextBuilder}
581      */
582     @Deprecated
583     public static SslContext newClientContext(TrustManagerFactory trustManagerFactory) throws SSLException {
584         return newClientContext(null, null, trustManagerFactory);
585     }
586 
587     /**
588      * Creates a new client-side {@link SslContext}.
589      *
590      * @param certChainFile an X.509 certificate chain file in PEM format.
591      *                      {@code null} to use the system default
592      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
593      *                            that verifies the certificates sent from servers.
594      *                            {@code null} to use the default.
595      *
596      * @return a new client-side {@link SslContext}
597      * @deprecated Replaced by {@link SslContextBuilder}
598      */
599     @Deprecated
600     public static SslContext newClientContext(
601             File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException {
602         return newClientContext(null, certChainFile, trustManagerFactory);
603     }
604 
605     /**
606      * Creates a new client-side {@link SslContext}.
607      *
608      * @param certChainFile an X.509 certificate chain file in PEM format.
609      *                      {@code null} to use the system default
610      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
611      *                            that verifies the certificates sent from servers.
612      *                            {@code null} to use the default.
613      * @param ciphers the cipher suites to enable, in the order of preference.
614      *                {@code null} to use the default cipher suites.
615      * @param nextProtocols the application layer protocols to accept, in the order of preference.
616      *                      {@code null} to disable TLS NPN/ALPN extension.
617      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
618      *                         {@code 0} to use the default value.
619      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
620      *                       {@code 0} to use the default value.
621      *
622      * @return a new client-side {@link SslContext}
623      * @deprecated Replaced by {@link SslContextBuilder}
624      */
625     @Deprecated
626     public static SslContext newClientContext(
627             File certChainFile, TrustManagerFactory trustManagerFactory,
628             Iterable<String> ciphers, Iterable<String> nextProtocols,
629             long sessionCacheSize, long sessionTimeout) throws SSLException {
630         return newClientContext(
631                 null, certChainFile, trustManagerFactory,
632                 ciphers, nextProtocols, sessionCacheSize, sessionTimeout);
633     }
634 
635     /**
636      * Creates a new client-side {@link SslContext}.
637      *
638      * @param certChainFile an X.509 certificate chain file in PEM format.
639      *                      {@code null} to use the system default
640      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
641      *                            that verifies the certificates sent from servers.
642      *                            {@code null} to use the default.
643      * @param ciphers the cipher suites to enable, in the order of preference.
644      *                {@code null} to use the default cipher suites.
645      * @param cipherFilter a filter to apply over the supplied list of ciphers
646      * @param apn Provides a means to configure parameters related to application protocol negotiation.
647      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
648      *                         {@code 0} to use the default value.
649      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
650      *                       {@code 0} to use the default value.
651      *
652      * @return a new client-side {@link SslContext}
653      * @deprecated Replaced by {@link SslContextBuilder}
654      */
655     @Deprecated
656     public static SslContext newClientContext(
657             File certChainFile, TrustManagerFactory trustManagerFactory,
658             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
659             long sessionCacheSize, long sessionTimeout) throws SSLException {
660         return newClientContext(
661                 null, certChainFile, trustManagerFactory,
662                 ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
663     }
664 
665     /**
666      * Creates a new client-side {@link SslContext}.
667      *
668      * @param provider the {@link SslContext} implementation to use.
669      *                 {@code null} to use the current default one.
670      *
671      * @return a new client-side {@link SslContext}
672      * @deprecated Replaced by {@link SslContextBuilder}
673      */
674     @Deprecated
675     public static SslContext newClientContext(SslProvider provider) throws SSLException {
676         return newClientContext(provider, null, null);
677     }
678 
679     /**
680      * Creates a new client-side {@link SslContext}.
681      *
682      * @param provider the {@link SslContext} implementation to use.
683      *                 {@code null} to use the current default one.
684      * @param certChainFile an X.509 certificate chain file in PEM format.
685      *                      {@code null} to use the system default
686      *
687      * @return a new client-side {@link SslContext}
688      * @deprecated Replaced by {@link SslContextBuilder}
689      */
690     @Deprecated
691     public static SslContext newClientContext(SslProvider provider, File certChainFile) throws SSLException {
692         return newClientContext(provider, certChainFile, null);
693     }
694 
695     /**
696      * Creates a new client-side {@link SslContext}.
697      *
698      * @param provider the {@link SslContext} implementation to use.
699      *                 {@code null} to use the current default one.
700      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
701      *                            that verifies the certificates sent from servers.
702      *                            {@code null} to use the default.
703      *
704      * @return a new client-side {@link SslContext}
705      * @deprecated Replaced by {@link SslContextBuilder}
706      */
707     @Deprecated
708     public static SslContext newClientContext(
709             SslProvider provider, TrustManagerFactory trustManagerFactory) throws SSLException {
710         return newClientContext(provider, null, trustManagerFactory);
711     }
712 
713     /**
714      * Creates a new client-side {@link SslContext}.
715      *
716      * @param provider the {@link SslContext} implementation to use.
717      *                 {@code null} to use the current default one.
718      * @param certChainFile an X.509 certificate chain file in PEM format.
719      *                      {@code null} to use the system default
720      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
721      *                            that verifies the certificates sent from servers.
722      *                            {@code null} to use the default.
723      *
724      * @return a new client-side {@link SslContext}
725      * @deprecated Replaced by {@link SslContextBuilder}
726      */
727     @Deprecated
728     public static SslContext newClientContext(
729             SslProvider provider, File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException {
730         return newClientContext(provider, certChainFile, trustManagerFactory, null, IdentityCipherSuiteFilter.INSTANCE,
731                 null, 0, 0);
732     }
733 
734     /**
735      * Creates a new client-side {@link SslContext}.
736      *
737      * @param provider the {@link SslContext} implementation to use.
738      *                 {@code null} to use the current default one.
739      * @param certChainFile an X.509 certificate chain file in PEM format.
740      *                      {@code null} to use the system default
741      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
742      *                            that verifies the certificates sent from servers.
743      *                            {@code null} to use the default.
744      * @param ciphers the cipher suites to enable, in the order of preference.
745      *                {@code null} to use the default cipher suites.
746      * @param nextProtocols the application layer protocols to accept, in the order of preference.
747      *                      {@code null} to disable TLS NPN/ALPN extension.
748      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
749      *                         {@code 0} to use the default value.
750      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
751      *                       {@code 0} to use the default value.
752      *
753      * @return a new client-side {@link SslContext}
754      * @deprecated Replaced by {@link SslContextBuilder}
755      */
756     @Deprecated
757     public static SslContext newClientContext(
758             SslProvider provider,
759             File certChainFile, TrustManagerFactory trustManagerFactory,
760             Iterable<String> ciphers, Iterable<String> nextProtocols,
761             long sessionCacheSize, long sessionTimeout) throws SSLException {
762         return newClientContext(
763                 provider, certChainFile, trustManagerFactory, null, null, null, null,
764                 ciphers, IdentityCipherSuiteFilter.INSTANCE,
765                 toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout);
766     }
767 
768     /**
769      * Creates a new client-side {@link SslContext}.
770      *
771      * @param provider the {@link SslContext} implementation to use.
772      *                 {@code null} to use the current default one.
773      * @param certChainFile an X.509 certificate chain file in PEM format.
774      *                      {@code null} to use the system default
775      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
776      *                            that verifies the certificates sent from servers.
777      *                            {@code null} to use the default.
778      * @param ciphers the cipher suites to enable, in the order of preference.
779      *                {@code null} to use the default cipher suites.
780      * @param cipherFilter a filter to apply over the supplied list of ciphers
781      * @param apn Provides a means to configure parameters related to application protocol negotiation.
782      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
783      *                         {@code 0} to use the default value.
784      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
785      *                       {@code 0} to use the default value.
786      *
787      * @return a new client-side {@link SslContext}
788      * @deprecated Replaced by {@link SslContextBuilder}
789      */
790     @Deprecated
791     public static SslContext newClientContext(
792             SslProvider provider,
793             File certChainFile, TrustManagerFactory trustManagerFactory,
794             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
795             long sessionCacheSize, long sessionTimeout) throws SSLException {
796 
797         return newClientContext(
798                 provider, certChainFile, trustManagerFactory, null, null, null, null,
799                 ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
800     }
801 
802     /**
803      * Creates a new client-side {@link SslContext}.
804      * @param provider the {@link SslContext} implementation to use.
805      *                 {@code null} to use the current default one.
806      * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
807      *                      {@code null} to use the system default
808      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
809      *                            that verifies the certificates sent from servers.
810      *                            {@code null} to use the default or the results of parsing
811      *                            {@code trustCertCollectionFile}.
812      *                            This parameter is ignored if {@code provider} is not {@link SslProvider#JDK}.
813      * @param keyCertChainFile an X.509 certificate chain file in PEM format.
814      *                      This provides the public key for mutual authentication.
815      *                      {@code null} to use the system default
816      * @param keyFile a PKCS#8 private key file in PEM format.
817      *                      This provides the private key for mutual authentication.
818      *                      {@code null} for no mutual authentication.
819      * @param keyPassword the password of the {@code keyFile}.
820      *                    {@code null} if it's not password-protected.
821      *                    Ignored if {@code keyFile} is {@code null}.
822      * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
823      *                          that is used to encrypt data being sent to servers.
824      *                          {@code null} to use the default or the results of parsing
825      *                          {@code keyCertChainFile} and {@code keyFile}.
826      *                          This parameter is ignored if {@code provider} is not {@link SslProvider#JDK}.
827      * @param ciphers the cipher suites to enable, in the order of preference.
828      *                {@code null} to use the default cipher suites.
829      * @param cipherFilter a filter to apply over the supplied list of ciphers
830      * @param apn Provides a means to configure parameters related to application protocol negotiation.
831      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
832      *                         {@code 0} to use the default value.
833      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
834      *                       {@code 0} to use the default value.
835      *
836      * @return a new client-side {@link SslContext}
837      * @deprecated Replaced by {@link SslContextBuilder}
838      */
839     @Deprecated
840     public static SslContext newClientContext(
841         SslProvider provider,
842         File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
843         File keyCertChainFile, File keyFile, String keyPassword,
844         KeyManagerFactory keyManagerFactory,
845         Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
846         long sessionCacheSize, long sessionTimeout) throws SSLException {
847         try {
848             return newClientContextInternal(provider, null,
849                                             toX509Certificates(trustCertCollectionFile), trustManagerFactory,
850                                             toX509Certificates(keyCertChainFile), toPrivateKey(keyFile, keyPassword),
851                                             keyPassword, keyManagerFactory, ciphers, cipherFilter,
852                                             apn, null, sessionCacheSize, sessionTimeout, false,
853                                             null, KeyStore.getDefaultType(),
854                                             defaultEndpointVerificationAlgorithm,
855                                             Collections.emptyList(), null, null);
856         } catch (Exception e) {
857             if (e instanceof SSLException) {
858                 throw (SSLException) e;
859             }
860             throw new SSLException("failed to initialize the client-side SSL context", e);
861         }
862     }
863 
864     static SslContext newClientContextInternal(
865             SslProvider provider,
866             Provider sslContextProvider,
867             X509Certificate[] trustCert, TrustManagerFactory trustManagerFactory,
868             X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
869             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols,
870             long sessionCacheSize, long sessionTimeout, boolean enableOcsp,
871             SecureRandom secureRandom, String keyStoreType, String endpointIdentificationAlgorithm,
872             List<SNIServerName> serverNames,
873             Map.Entry<SslContextOption<?>, Object>[] options,
874             List<OpenSslCredential> credentials) throws SSLException {
875         if (provider == null) {
876             provider = defaultClientProvider();
877         }
878 
879         ResumptionController resumptionController = new ResumptionController();
880 
881         switch (provider) {
882             case JDK:
883                 if (enableOcsp) {
884                     throw new IllegalArgumentException("OCSP is not supported with this SslProvider: " + provider);
885                 }
886                 if (credentials != null && !credentials.isEmpty()) {
887                     throw new IllegalArgumentException(
888                             "OpenSslCredential is not supported with SslProvider.JDK. " +
889                                     "Use SslProvider.OPENSSL or SslProvider.OPENSSL_REFCNT instead.");
890                 }
891                 return new JdkSslClientContext(sslContextProvider,
892                         trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
893                         keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize,
894                         sessionTimeout, secureRandom, keyStoreType, endpointIdentificationAlgorithm,
895                         serverNames, resumptionController);
896             case OPENSSL:
897                 verifyNullSslContextProvider(provider, sslContextProvider);
898                 OpenSsl.ensureAvailability();
899                 return new OpenSslClientContext(
900                         trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
901                         keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
902                         enableOcsp, keyStoreType, endpointIdentificationAlgorithm, serverNames, resumptionController,
903                         options, credentials);
904             case OPENSSL_REFCNT:
905                 verifyNullSslContextProvider(provider, sslContextProvider);
906                 OpenSsl.ensureAvailability();
907                 return new ReferenceCountedOpenSslClientContext(
908                         trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
909                         keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
910                         enableOcsp, keyStoreType, endpointIdentificationAlgorithm, serverNames, resumptionController,
911                         options, credentials);
912             default:
913                 throw new Error("Unexpected provider: " + provider);
914         }
915     }
916 
917     static ApplicationProtocolConfig toApplicationProtocolConfig(Iterable<String> nextProtocols) {
918         ApplicationProtocolConfig apn;
919         if (nextProtocols == null) {
920             apn = ApplicationProtocolConfig.DISABLED;
921         } else {
922             apn = new ApplicationProtocolConfig(
923                     Protocol.NPN_AND_ALPN, SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL,
924                     SelectedListenerFailureBehavior.ACCEPT, nextProtocols);
925         }
926         return apn;
927     }
928 
929     /**
930      * Creates a new instance (startTls set to {@code false}).
931      */
932     protected SslContext() {
933         this(false);
934     }
935 
936     /**
937      * Creates a new instance.
938      */
939     protected SslContext(boolean startTls) {
940         this(startTls, null);
941     }
942 
943     SslContext(boolean startTls, ResumptionController resumptionController) {
944         this.startTls = startTls;
945         this.resumptionController = resumptionController;
946     }
947 
948     /**
949      * Returns the {@link AttributeMap} that belongs to this {@link SslContext} .
950      */
951     public final AttributeMap attributes() {
952         return attributes;
953     }
954 
955     /**
956      * Returns {@code true} if and only if this context is for server-side.
957      */
958     public final boolean isServer() {
959         return !isClient();
960     }
961 
962     /**
963      * Returns the {@code true} if and only if this context is for client-side.
964      */
965     public abstract boolean isClient();
966 
967     /**
968      * Returns the list of enabled cipher suites, in the order of preference.
969      */
970     public abstract List<String> cipherSuites();
971 
972     /**
973      * Returns the size of the cache used for storing SSL session objects.
974      */
975     public long sessionCacheSize() {
976         return sessionContext().getSessionCacheSize();
977     }
978 
979     /**
980      * Returns the timeout for the cached SSL session objects, in seconds.
981      */
982     public long sessionTimeout() {
983         return sessionContext().getSessionTimeout();
984     }
985 
986     /**
987      * @deprecated Use {@link #applicationProtocolNegotiator()} instead.
988      */
989     @Deprecated
990     public final List<String> nextProtocols() {
991         return applicationProtocolNegotiator().protocols();
992     }
993 
994     /**
995      * Returns the object responsible for negotiating application layer protocols for the TLS NPN/ALPN extensions.
996      */
997     public abstract ApplicationProtocolNegotiator applicationProtocolNegotiator();
998 
999     /**
1000      * Creates a new {@link SSLEngine}.
1001      * <p>If {@link SslProvider#OPENSSL_REFCNT} is used then the object must be released. One way to do this is to
1002      * wrap in a {@link SslHandler} and insert it into a pipeline. See {@link #newHandler(ByteBufAllocator)}.
1003      * @return a new {@link SSLEngine}
1004      */
1005     public abstract SSLEngine newEngine(ByteBufAllocator alloc);
1006 
1007     /**
1008      * Creates a new {@link SSLEngine} using advisory peer information.
1009      * <p>If {@link SslProvider#OPENSSL_REFCNT} is used then the object must be released. One way to do this is to
1010      * wrap in a {@link SslHandler} and insert it into a pipeline.
1011      * See {@link #newHandler(ByteBufAllocator, String, int)}.
1012      * @param peerHost the non-authoritative name of the host
1013      * @param peerPort the non-authoritative port
1014      *
1015      * @return a new {@link SSLEngine}
1016      */
1017     public abstract SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort);
1018 
1019     /**
1020      * Returns the {@link SSLSessionContext} object held by this context.
1021      */
1022     public abstract SSLSessionContext sessionContext();
1023 
1024     /**
1025      * Create a new SslHandler.
1026      * @see #newHandler(ByteBufAllocator, Executor)
1027      */
1028     public final SslHandler newHandler(ByteBufAllocator alloc) {
1029         return newHandler(alloc, startTls);
1030     }
1031 
1032     /**
1033      * Create a new SslHandler.
1034      * @see #newHandler(ByteBufAllocator)
1035      */
1036     protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) {
1037         return new SslHandler(newEngine(alloc), startTls, ImmediateExecutor.INSTANCE, resumptionController);
1038     }
1039 
1040     /**
1041      * Creates a new {@link SslHandler}.
1042      * <p>If {@link SslProvider#OPENSSL_REFCNT} is used then the returned {@link SslHandler} will release the engine
1043      * that is wrapped. If the returned {@link SslHandler} is not inserted into a pipeline then you may leak native
1044      * memory!
1045      * <p><b>Beware</b>: the underlying generated {@link SSLEngine} won't have
1046      * <a href="https://wiki.openssl.org/index.php/Hostname_validation">hostname verification</a> enabled by default.
1047      * If you create {@link SslHandler} for the client side and want proper security, we advice that you configure
1048      * the {@link SSLEngine} (see {@link javax.net.ssl.SSLParameters#setEndpointIdentificationAlgorithm(String)}):
1049      * <pre>
1050      * SSLEngine sslEngine = sslHandler.engine();
1051      * SSLParameters sslParameters = sslEngine.getSSLParameters();
1052      * // only available since Java 7
1053      * sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
1054      * sslEngine.setSSLParameters(sslParameters);
1055      * </pre>
1056      * <p>
1057      * The underlying {@link SSLEngine} may not follow the restrictions imposed by the
1058      * <a href="https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html">SSLEngine javadocs</a> which
1059      * limits wrap/unwrap to operate on a single SSL/TLS packet.
1060      * @param alloc If supported by the SSLEngine then the SSLEngine will use this to allocate ByteBuf objects.
1061      * @param delegatedTaskExecutor the {@link Executor} that will be used to execute tasks that are returned by
1062      *                              {@link SSLEngine#getDelegatedTask()}.
1063      * @return a new {@link SslHandler}
1064      */
1065     public SslHandler newHandler(ByteBufAllocator alloc, Executor delegatedTaskExecutor) {
1066         return newHandler(alloc, startTls, delegatedTaskExecutor);
1067     }
1068 
1069     /**
1070      * Create a new SslHandler.
1071      * @see #newHandler(ByteBufAllocator, String, int, boolean, Executor)
1072      */
1073     protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls, Executor executor) {
1074         return new SslHandler(newEngine(alloc), startTls, executor, resumptionController);
1075     }
1076 
1077     /**
1078      * Creates a new {@link SslHandler}
1079      *
1080      * @see #newHandler(ByteBufAllocator, String, int, Executor)
1081      */
1082     public final SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort) {
1083         return newHandler(alloc, peerHost, peerPort, startTls);
1084     }
1085 
1086     /**
1087      * Create a new SslHandler.
1088      * @see #newHandler(ByteBufAllocator, String, int, boolean, Executor)
1089      */
1090     protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls) {
1091         return new SslHandler(newEngine(alloc, peerHost, peerPort), startTls, ImmediateExecutor.INSTANCE,
1092                 resumptionController);
1093     }
1094 
1095     /**
1096      * Creates a new {@link SslHandler} with advisory peer information.
1097      * <p>If {@link SslProvider#OPENSSL_REFCNT} is used then the returned {@link SslHandler} will release the engine
1098      * that is wrapped. If the returned {@link SslHandler} is not inserted into a pipeline then you may leak native
1099      * memory!
1100      * <p><b>Beware</b>: the underlying generated {@link SSLEngine} won't have
1101      * <a href="https://wiki.openssl.org/index.php/Hostname_validation">hostname verification</a> enabled by default.
1102      * If you create {@link SslHandler} for the client side and want proper security, we advice that you configure
1103      * the {@link SSLEngine} (see {@link javax.net.ssl.SSLParameters#setEndpointIdentificationAlgorithm(String)}):
1104      * <pre>
1105      * SSLEngine sslEngine = sslHandler.engine();
1106      * SSLParameters sslParameters = sslEngine.getSSLParameters();
1107      * // only available since Java 7
1108      * sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
1109      * sslEngine.setSSLParameters(sslParameters);
1110      * </pre>
1111      * <p>
1112      * The underlying {@link SSLEngine} may not follow the restrictions imposed by the
1113      * <a href="https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html">SSLEngine javadocs</a> which
1114      * limits wrap/unwrap to operate on a single SSL/TLS packet.
1115      * @param alloc If supported by the SSLEngine then the SSLEngine will use this to allocate ByteBuf objects.
1116      * @param peerHost the non-authoritative name of the host
1117      * @param peerPort the non-authoritative port
1118      * @param delegatedTaskExecutor the {@link Executor} that will be used to execute tasks that are returned by
1119      *                              {@link SSLEngine#getDelegatedTask()}.
1120      *
1121      * @return a new {@link SslHandler}
1122      */
1123     public SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort,
1124                                  Executor delegatedTaskExecutor) {
1125         return newHandler(alloc, peerHost, peerPort, startTls, delegatedTaskExecutor);
1126     }
1127 
1128     protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls,
1129                                     Executor delegatedTaskExecutor) {
1130         return new SslHandler(newEngine(alloc, peerHost, peerPort), startTls, delegatedTaskExecutor,
1131                 resumptionController);
1132     }
1133 
1134     /**
1135      * Generates a key specification for an (encrypted) private key.
1136      *
1137      * @param password characters, if {@code null} an unencrypted key is assumed
1138      * @param key bytes of the DER encoded private key
1139      *
1140      * @return a key specification
1141      *
1142      * @throws IOException if parsing {@code key} fails
1143      * @throws NoSuchAlgorithmException if the algorithm used to encrypt {@code key} is unknown
1144      * @throws NoSuchPaddingException if the padding scheme specified in the decryption algorithm is unknown
1145      * @throws InvalidKeySpecException if the decryption key based on {@code password} cannot be generated
1146      * @throws InvalidKeyException if the decryption key based on {@code password} cannot be used to decrypt
1147      *                             {@code key}
1148      * @throws InvalidAlgorithmParameterException if decryption algorithm parameters are somehow faulty
1149      */
1150     @Deprecated
1151     protected static PKCS8EncodedKeySpec generateKeySpec(char[] password, byte[] key)
1152             throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException,
1153             InvalidKeyException, InvalidAlgorithmParameterException {
1154 
1155         if (password == null) {
1156             return new PKCS8EncodedKeySpec(key);
1157         }
1158 
1159         EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = new EncryptedPrivateKeyInfo(key);
1160         String pbeAlgorithm = getPBEAlgorithm(encryptedPrivateKeyInfo);
1161         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(pbeAlgorithm);
1162         PBEKeySpec pbeKeySpec = new PBEKeySpec(password);
1163         SecretKey pbeKey = keyFactory.generateSecret(pbeKeySpec);
1164 
1165         Cipher cipher = Cipher.getInstance(pbeAlgorithm);
1166         cipher.init(Cipher.DECRYPT_MODE, pbeKey, encryptedPrivateKeyInfo.getAlgParameters());
1167 
1168         return encryptedPrivateKeyInfo.getKeySpec(cipher);
1169     }
1170 
1171     private static String getPBEAlgorithm(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo) {
1172         AlgorithmParameters parameters = encryptedPrivateKeyInfo.getAlgParameters();
1173         String algName = encryptedPrivateKeyInfo.getAlgName();
1174         // Java 8 ~ 16 returns OID_PKCS5_PBES2
1175         // Java 17+ returns PBES2
1176         if (parameters != null && (OID_PKCS5_PBES2.equals(algName) || PBES2.equals(algName))) {
1177             /*
1178              * This should be "PBEWith<prf>And<encryption>".
1179              * Relying on the toString() implementation is potentially
1180              * fragile but acceptable in this case since the JRE depends on
1181              * the toString() implementation as well.
1182              * In the future, if necessary, we can parse the value of
1183              * parameters.getEncoded() but the associated complexity and
1184              * unlikeliness of the JRE implementation changing means that
1185              * Tomcat will use to toString() approach for now.
1186              */
1187             return parameters.toString();
1188         }
1189         return encryptedPrivateKeyInfo.getAlgName();
1190     }
1191 
1192     /**
1193      * Generates a new {@link KeyStore}.
1194      *
1195      * @param certChain an X.509 certificate chain
1196      * @param key a PKCS#8 private key
1197      * @param keyPasswordChars the password of the {@code keyFile}.
1198      *                    {@code null} if it's not password-protected.
1199      * @param keyStoreType The KeyStore Type you want to use
1200      * @return generated {@link KeyStore}.
1201      */
1202     protected static KeyStore buildKeyStore(X509Certificate[] certChain, PrivateKey key,
1203                                   char[] keyPasswordChars, String keyStoreType)
1204             throws KeyStoreException, NoSuchAlgorithmException,
1205                    CertificateException, IOException {
1206         if (keyStoreType == null) {
1207             keyStoreType = KeyStore.getDefaultType();
1208         }
1209         KeyStore ks = KeyStore.getInstance(keyStoreType);
1210         ks.load(null, null);
1211         ks.setKeyEntry(ALIAS, key, keyPasswordChars, certChain);
1212         return ks;
1213     }
1214 
1215     protected static PrivateKey toPrivateKey(File keyFile, String keyPassword) throws NoSuchAlgorithmException,
1216                                                                 NoSuchPaddingException, InvalidKeySpecException,
1217                                                                 InvalidAlgorithmParameterException,
1218                                                                 KeyException, IOException {
1219         return toPrivateKey(keyFile, keyPassword, true);
1220     }
1221 
1222     static PrivateKey toPrivateKey(File keyFile, String keyPassword, boolean tryBouncyCastle)
1223             throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException,
1224             InvalidAlgorithmParameterException,
1225             KeyException, IOException {
1226         if (keyFile == null) {
1227             return null;
1228         }
1229 
1230         // try BC first, if this fail fallback to original key extraction process
1231         if (tryBouncyCastle && BouncyCastleUtil.isBcPkixAvailable()) {
1232             PrivateKey pk = BouncyCastlePemReader.getPrivateKey(keyFile, keyPassword);
1233             if (pk != null) {
1234                 return pk;
1235             }
1236         }
1237 
1238         return getPrivateKeyFromByteBuffer(PemReader.readPrivateKey(keyFile), keyPassword);
1239     }
1240 
1241     protected static PrivateKey toPrivateKey(InputStream keyInputStream, String keyPassword)
1242                                                                 throws NoSuchAlgorithmException,
1243                                                                 NoSuchPaddingException, InvalidKeySpecException,
1244                                                                 InvalidAlgorithmParameterException,
1245                                                                 KeyException, IOException {
1246         if (keyInputStream == null) {
1247             return null;
1248         }
1249 
1250         // try BC first, if this fail fallback to original key extraction process
1251         if (BouncyCastleUtil.isBcPkixAvailable()) {
1252             if (!keyInputStream.markSupported()) {
1253                 // We need an input stream that supports resetting, in case BouncyCastle fails to read.
1254                 keyInputStream = new BufferedInputStream(keyInputStream);
1255             }
1256             keyInputStream.mark(1048576); // Be able to reset up to 1 MiB of data.
1257             PrivateKey pk = BouncyCastlePemReader.getPrivateKey(keyInputStream, keyPassword);
1258             if (pk != null) {
1259                 return pk;
1260             }
1261             // BouncyCastle could not read the key. Reset the input stream in case the input position changed.
1262             keyInputStream.reset();
1263         }
1264 
1265         return getPrivateKeyFromByteBuffer(PemReader.readPrivateKey(keyInputStream), keyPassword);
1266     }
1267 
1268     private static PrivateKey getPrivateKeyFromByteBuffer(ByteBuf encodedKeyBuf, String keyPassword)
1269             throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException,
1270             InvalidAlgorithmParameterException, KeyException, IOException {
1271 
1272         byte[] encodedKey = new byte[encodedKeyBuf.readableBytes()];
1273         encodedKeyBuf.readBytes(encodedKey).release();
1274 
1275         PKCS8EncodedKeySpec encodedKeySpec = generateKeySpec(
1276                 keyPassword == null ? null : keyPassword.toCharArray(), encodedKey);
1277         try {
1278             return KeyFactory.getInstance("RSA").generatePrivate(encodedKeySpec);
1279         } catch (InvalidKeySpecException ignore) {
1280             try {
1281                 return KeyFactory.getInstance("DSA").generatePrivate(encodedKeySpec);
1282             } catch (InvalidKeySpecException ignore2) {
1283                 try {
1284                     return KeyFactory.getInstance("EC").generatePrivate(encodedKeySpec);
1285                 } catch (InvalidKeySpecException e) {
1286                     throw new InvalidKeySpecException("Neither RSA, DSA nor EC worked", e);
1287                 }
1288             }
1289         }
1290     }
1291 
1292     /**
1293      * Build a {@link TrustManagerFactory} from a certificate chain file.
1294      * @param certChainFile The certificate file to build from.
1295      * @param trustManagerFactory The existing {@link TrustManagerFactory} that will be used if not {@code null}.
1296      * @return A {@link TrustManagerFactory} which contains the certificates in {@code certChainFile}
1297      */
1298     @Deprecated
1299     protected static TrustManagerFactory buildTrustManagerFactory(
1300             File certChainFile, TrustManagerFactory trustManagerFactory)
1301             throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
1302         return buildTrustManagerFactory(certChainFile, trustManagerFactory, null);
1303     }
1304 
1305     /**
1306      * Build a {@link TrustManagerFactory} from a certificate chain file.
1307      * @param certChainFile The certificate file to build from.
1308      * @param trustManagerFactory The existing {@link TrustManagerFactory} that will be used if not {@code null}.
1309      * @param keyType The KeyStore Type you want to use
1310      * @return A {@link TrustManagerFactory} which contains the certificates in {@code certChainFile}
1311      */
1312     protected static TrustManagerFactory buildTrustManagerFactory(
1313             File certChainFile, TrustManagerFactory trustManagerFactory, String keyType)
1314             throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
1315         X509Certificate[] x509Certs = toX509Certificates(certChainFile);
1316 
1317         return buildTrustManagerFactory(x509Certs, trustManagerFactory, keyType);
1318     }
1319 
1320     protected static X509Certificate[] toX509Certificates(File file) throws CertificateException {
1321         if (file == null) {
1322             return null;
1323         }
1324         return getCertificatesFromBuffers(PemReader.readCertificates(file));
1325     }
1326 
1327     protected static X509Certificate[] toX509Certificates(InputStream in) throws CertificateException {
1328         if (in == null) {
1329             return null;
1330         }
1331         return getCertificatesFromBuffers(PemReader.readCertificates(in));
1332     }
1333 
1334     private static X509Certificate[] getCertificatesFromBuffers(ByteBuf[] certs) throws CertificateException {
1335         CertificateFactory cf = CertificateFactory.getInstance("X.509");
1336         X509Certificate[] x509Certs = new X509Certificate[certs.length];
1337 
1338         try {
1339             for (int i = 0; i < certs.length; i++) {
1340                 try (InputStream is = new ByteBufInputStream(certs[i], false)) {
1341                     x509Certs[i] = (X509Certificate) cf.generateCertificate(is);
1342                 } catch (IOException e) {
1343                     // This is not expected to happen, but re-throw in case it does.
1344                     throw new RuntimeException(e);
1345                 }
1346             }
1347         } finally {
1348             for (ByteBuf buf: certs) {
1349                 buf.release();
1350             }
1351         }
1352         return x509Certs;
1353     }
1354 
1355     protected static TrustManagerFactory buildTrustManagerFactory(
1356             X509Certificate[] certCollection, TrustManagerFactory trustManagerFactory, String keyStoreType)
1357             throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
1358         if (keyStoreType == null) {
1359             keyStoreType = KeyStore.getDefaultType();
1360         }
1361         final KeyStore ks = KeyStore.getInstance(keyStoreType);
1362         ks.load(null, null);
1363 
1364         int i = 1;
1365         for (X509Certificate cert: certCollection) {
1366             String alias = Integer.toString(i);
1367             ks.setCertificateEntry(alias, cert);
1368             i++;
1369         }
1370 
1371         // Set up trust manager factory to use our key store.
1372         if (trustManagerFactory == null) {
1373             trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
1374         }
1375         trustManagerFactory.init(ks);
1376 
1377         return trustManagerFactory;
1378     }
1379 
1380     static PrivateKey toPrivateKeyInternal(File keyFile, String keyPassword) throws SSLException {
1381         try {
1382             return toPrivateKey(keyFile, keyPassword);
1383         } catch (Exception e) {
1384             throw new SSLException(e);
1385         }
1386     }
1387 
1388     static X509Certificate[] toX509CertificatesInternal(File file) throws SSLException {
1389         try {
1390             return toX509Certificates(file);
1391         } catch (CertificateException e) {
1392             throw new SSLException(e);
1393         }
1394     }
1395 
1396     protected static KeyManagerFactory buildKeyManagerFactory(X509Certificate[] certChainFile,
1397                                                     String keyAlgorithm, PrivateKey key,
1398                                                     String keyPassword, KeyManagerFactory kmf,
1399                                                     String keyStore)
1400             throws KeyStoreException, NoSuchAlgorithmException, IOException,
1401             CertificateException, UnrecoverableKeyException {
1402         if (keyAlgorithm == null) {
1403             keyAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
1404         }
1405         char[] keyPasswordChars = keyStorePassword(keyPassword);
1406         KeyStore ks = buildKeyStore(certChainFile, key, keyPasswordChars, keyStore);
1407         return buildKeyManagerFactory(ks, keyAlgorithm, keyPasswordChars, kmf);
1408     }
1409 
1410     static KeyManagerFactory buildKeyManagerFactory(KeyStore ks,
1411                                                     String keyAlgorithm,
1412                                                     char[] keyPasswordChars, KeyManagerFactory kmf)
1413             throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
1414         // Set up key manager factory to use our key store
1415         if (kmf == null) {
1416             if (keyAlgorithm == null) {
1417                 keyAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
1418             }
1419             kmf = KeyManagerFactory.getInstance(keyAlgorithm);
1420         }
1421         kmf.init(ks, keyPasswordChars);
1422 
1423         return kmf;
1424     }
1425 
1426     static char[] keyStorePassword(String keyPassword) {
1427         return keyPassword == null ? EmptyArrays.EMPTY_CHARS : keyPassword.toCharArray();
1428     }
1429 }