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                     credentials);
531         case OPENSSL_REFCNT:
532             verifyNullSslContextProvider(provider, sslContextProvider);
533             return new ReferenceCountedOpenSslServerContext(
534                     trustCertCollection, trustManagerFactory, keyCertChain, key, keyPassword,
535                     keyManagerFactory, ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout,
536                     clientAuth, protocols, startTls, enableOcsp, keyStoreType, resumptionController, ctxOptions,
537                     credentials);
538         default:
539             throw new Error("Unexpected provider: " + provider);
540         }
541     }
542 
543     private static void verifyNullSslContextProvider(SslProvider provider, Provider sslContextProvider) {
544         if (sslContextProvider != null) {
545             throw new IllegalArgumentException("Java Security Provider unsupported for SslProvider: " + provider);
546         }
547     }
548 
549     /**
550      * Creates a new client-side {@link SslContext}.
551      *
552      * @return a new client-side {@link SslContext}
553      * @deprecated Replaced by {@link SslContextBuilder}
554      */
555     @Deprecated
556     public static SslContext newClientContext() throws SSLException {
557         return newClientContext(null, null, null);
558     }
559 
560     /**
561      * Creates a new client-side {@link SslContext}.
562      *
563      * @param certChainFile an X.509 certificate chain file in PEM format
564      *
565      * @return a new client-side {@link SslContext}
566      * @deprecated Replaced by {@link SslContextBuilder}
567      */
568     @Deprecated
569     public static SslContext newClientContext(File certChainFile) throws SSLException {
570         return newClientContext(null, certChainFile);
571     }
572 
573     /**
574      * Creates a new client-side {@link SslContext}.
575      *
576      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
577      *                            that verifies the certificates sent from servers.
578      *                            {@code null} to use the default.
579      *
580      * @return a new client-side {@link SslContext}
581      * @deprecated Replaced by {@link SslContextBuilder}
582      */
583     @Deprecated
584     public static SslContext newClientContext(TrustManagerFactory trustManagerFactory) throws SSLException {
585         return newClientContext(null, null, trustManagerFactory);
586     }
587 
588     /**
589      * Creates a new client-side {@link SslContext}.
590      *
591      * @param certChainFile an X.509 certificate chain file in PEM format.
592      *                      {@code null} to use the system default
593      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
594      *                            that verifies the certificates sent from servers.
595      *                            {@code null} to use the default.
596      *
597      * @return a new client-side {@link SslContext}
598      * @deprecated Replaced by {@link SslContextBuilder}
599      */
600     @Deprecated
601     public static SslContext newClientContext(
602             File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException {
603         return newClientContext(null, certChainFile, trustManagerFactory);
604     }
605 
606     /**
607      * Creates a new client-side {@link SslContext}.
608      *
609      * @param certChainFile an X.509 certificate chain file in PEM format.
610      *                      {@code null} to use the system default
611      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
612      *                            that verifies the certificates sent from servers.
613      *                            {@code null} to use the default.
614      * @param ciphers the cipher suites to enable, in the order of preference.
615      *                {@code null} to use the default cipher suites.
616      * @param nextProtocols the application layer protocols to accept, in the order of preference.
617      *                      {@code null} to disable TLS NPN/ALPN extension.
618      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
619      *                         {@code 0} to use the default value.
620      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
621      *                       {@code 0} to use the default value.
622      *
623      * @return a new client-side {@link SslContext}
624      * @deprecated Replaced by {@link SslContextBuilder}
625      */
626     @Deprecated
627     public static SslContext newClientContext(
628             File certChainFile, TrustManagerFactory trustManagerFactory,
629             Iterable<String> ciphers, Iterable<String> nextProtocols,
630             long sessionCacheSize, long sessionTimeout) throws SSLException {
631         return newClientContext(
632                 null, certChainFile, trustManagerFactory,
633                 ciphers, nextProtocols, sessionCacheSize, sessionTimeout);
634     }
635 
636     /**
637      * Creates a new client-side {@link SslContext}.
638      *
639      * @param certChainFile an X.509 certificate chain file in PEM format.
640      *                      {@code null} to use the system default
641      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
642      *                            that verifies the certificates sent from servers.
643      *                            {@code null} to use the default.
644      * @param ciphers the cipher suites to enable, in the order of preference.
645      *                {@code null} to use the default cipher suites.
646      * @param cipherFilter a filter to apply over the supplied list of ciphers
647      * @param apn Provides a means to configure parameters related to application protocol negotiation.
648      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
649      *                         {@code 0} to use the default value.
650      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
651      *                       {@code 0} to use the default value.
652      *
653      * @return a new client-side {@link SslContext}
654      * @deprecated Replaced by {@link SslContextBuilder}
655      */
656     @Deprecated
657     public static SslContext newClientContext(
658             File certChainFile, TrustManagerFactory trustManagerFactory,
659             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
660             long sessionCacheSize, long sessionTimeout) throws SSLException {
661         return newClientContext(
662                 null, certChainFile, trustManagerFactory,
663                 ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
664     }
665 
666     /**
667      * Creates a new client-side {@link SslContext}.
668      *
669      * @param provider the {@link SslContext} implementation to use.
670      *                 {@code null} to use the current default one.
671      *
672      * @return a new client-side {@link SslContext}
673      * @deprecated Replaced by {@link SslContextBuilder}
674      */
675     @Deprecated
676     public static SslContext newClientContext(SslProvider provider) throws SSLException {
677         return newClientContext(provider, null, null);
678     }
679 
680     /**
681      * Creates a new client-side {@link SslContext}.
682      *
683      * @param provider the {@link SslContext} implementation to use.
684      *                 {@code null} to use the current default one.
685      * @param certChainFile an X.509 certificate chain file in PEM format.
686      *                      {@code null} to use the system default
687      *
688      * @return a new client-side {@link SslContext}
689      * @deprecated Replaced by {@link SslContextBuilder}
690      */
691     @Deprecated
692     public static SslContext newClientContext(SslProvider provider, File certChainFile) throws SSLException {
693         return newClientContext(provider, certChainFile, null);
694     }
695 
696     /**
697      * Creates a new client-side {@link SslContext}.
698      *
699      * @param provider the {@link SslContext} implementation to use.
700      *                 {@code null} to use the current default one.
701      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
702      *                            that verifies the certificates sent from servers.
703      *                            {@code null} to use the default.
704      *
705      * @return a new client-side {@link SslContext}
706      * @deprecated Replaced by {@link SslContextBuilder}
707      */
708     @Deprecated
709     public static SslContext newClientContext(
710             SslProvider provider, TrustManagerFactory trustManagerFactory) throws SSLException {
711         return newClientContext(provider, null, trustManagerFactory);
712     }
713 
714     /**
715      * Creates a new client-side {@link SslContext}.
716      *
717      * @param provider the {@link SslContext} implementation to use.
718      *                 {@code null} to use the current default one.
719      * @param certChainFile an X.509 certificate chain file in PEM format.
720      *                      {@code null} to use the system default
721      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
722      *                            that verifies the certificates sent from servers.
723      *                            {@code null} to use the default.
724      *
725      * @return a new client-side {@link SslContext}
726      * @deprecated Replaced by {@link SslContextBuilder}
727      */
728     @Deprecated
729     public static SslContext newClientContext(
730             SslProvider provider, File certChainFile, TrustManagerFactory trustManagerFactory) throws SSLException {
731         return newClientContext(provider, certChainFile, trustManagerFactory, null, IdentityCipherSuiteFilter.INSTANCE,
732                 null, 0, 0);
733     }
734 
735     /**
736      * Creates a new client-side {@link SslContext}.
737      *
738      * @param provider the {@link SslContext} implementation to use.
739      *                 {@code null} to use the current default one.
740      * @param certChainFile an X.509 certificate chain file in PEM format.
741      *                      {@code null} to use the system default
742      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
743      *                            that verifies the certificates sent from servers.
744      *                            {@code null} to use the default.
745      * @param ciphers the cipher suites to enable, in the order of preference.
746      *                {@code null} to use the default cipher suites.
747      * @param nextProtocols the application layer protocols to accept, in the order of preference.
748      *                      {@code null} to disable TLS NPN/ALPN extension.
749      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
750      *                         {@code 0} to use the default value.
751      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
752      *                       {@code 0} to use the default value.
753      *
754      * @return a new client-side {@link SslContext}
755      * @deprecated Replaced by {@link SslContextBuilder}
756      */
757     @Deprecated
758     public static SslContext newClientContext(
759             SslProvider provider,
760             File certChainFile, TrustManagerFactory trustManagerFactory,
761             Iterable<String> ciphers, Iterable<String> nextProtocols,
762             long sessionCacheSize, long sessionTimeout) throws SSLException {
763         return newClientContext(
764                 provider, certChainFile, trustManagerFactory, null, null, null, null,
765                 ciphers, IdentityCipherSuiteFilter.INSTANCE,
766                 toApplicationProtocolConfig(nextProtocols), sessionCacheSize, sessionTimeout);
767     }
768 
769     /**
770      * Creates a new client-side {@link SslContext}.
771      *
772      * @param provider the {@link SslContext} implementation to use.
773      *                 {@code null} to use the current default one.
774      * @param certChainFile an X.509 certificate chain file in PEM format.
775      *                      {@code null} to use the system default
776      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
777      *                            that verifies the certificates sent from servers.
778      *                            {@code null} to use the default.
779      * @param ciphers the cipher suites to enable, in the order of preference.
780      *                {@code null} to use the default cipher suites.
781      * @param cipherFilter a filter to apply over the supplied list of ciphers
782      * @param apn Provides a means to configure parameters related to application protocol negotiation.
783      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
784      *                         {@code 0} to use the default value.
785      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
786      *                       {@code 0} to use the default value.
787      *
788      * @return a new client-side {@link SslContext}
789      * @deprecated Replaced by {@link SslContextBuilder}
790      */
791     @Deprecated
792     public static SslContext newClientContext(
793             SslProvider provider,
794             File certChainFile, TrustManagerFactory trustManagerFactory,
795             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
796             long sessionCacheSize, long sessionTimeout) throws SSLException {
797 
798         return newClientContext(
799                 provider, certChainFile, trustManagerFactory, null, null, null, null,
800                 ciphers, cipherFilter, apn, sessionCacheSize, sessionTimeout);
801     }
802 
803     /**
804      * Creates a new client-side {@link SslContext}.
805      * @param provider the {@link SslContext} implementation to use.
806      *                 {@code null} to use the current default one.
807      * @param trustCertCollectionFile an X.509 certificate collection file in PEM format.
808      *                      {@code null} to use the system default
809      * @param trustManagerFactory the {@link TrustManagerFactory} that provides the {@link TrustManager}s
810      *                            that verifies the certificates sent from servers.
811      *                            {@code null} to use the default or the results of parsing
812      *                            {@code trustCertCollectionFile}.
813      *                            This parameter is ignored if {@code provider} is not {@link SslProvider#JDK}.
814      * @param keyCertChainFile an X.509 certificate chain file in PEM format.
815      *                      This provides the public key for mutual authentication.
816      *                      {@code null} to use the system default
817      * @param keyFile a PKCS#8 private key file in PEM format.
818      *                      This provides the private key for mutual authentication.
819      *                      {@code null} for no mutual authentication.
820      * @param keyPassword the password of the {@code keyFile}.
821      *                    {@code null} if it's not password-protected.
822      *                    Ignored if {@code keyFile} is {@code null}.
823      * @param keyManagerFactory the {@link KeyManagerFactory} that provides the {@link KeyManager}s
824      *                          that is used to encrypt data being sent to servers.
825      *                          {@code null} to use the default or the results of parsing
826      *                          {@code keyCertChainFile} and {@code keyFile}.
827      *                          This parameter is ignored if {@code provider} is not {@link SslProvider#JDK}.
828      * @param ciphers the cipher suites to enable, in the order of preference.
829      *                {@code null} to use the default cipher suites.
830      * @param cipherFilter a filter to apply over the supplied list of ciphers
831      * @param apn Provides a means to configure parameters related to application protocol negotiation.
832      * @param sessionCacheSize the size of the cache used for storing SSL session objects.
833      *                         {@code 0} to use the default value.
834      * @param sessionTimeout the timeout for the cached SSL session objects, in seconds.
835      *                       {@code 0} to use the default value.
836      *
837      * @return a new client-side {@link SslContext}
838      * @deprecated Replaced by {@link SslContextBuilder}
839      */
840     @Deprecated
841     public static SslContext newClientContext(
842         SslProvider provider,
843         File trustCertCollectionFile, TrustManagerFactory trustManagerFactory,
844         File keyCertChainFile, File keyFile, String keyPassword,
845         KeyManagerFactory keyManagerFactory,
846         Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn,
847         long sessionCacheSize, long sessionTimeout) throws SSLException {
848         try {
849             return newClientContextInternal(provider, null,
850                                             toX509Certificates(trustCertCollectionFile), trustManagerFactory,
851                                             toX509Certificates(keyCertChainFile), toPrivateKey(keyFile, keyPassword),
852                                             keyPassword, keyManagerFactory, ciphers, cipherFilter,
853                                             apn, null, sessionCacheSize, sessionTimeout, false,
854                                             null, KeyStore.getDefaultType(),
855                                             defaultEndpointVerificationAlgorithm,
856                                             Collections.emptyList(), null, null);
857         } catch (Exception e) {
858             if (e instanceof SSLException) {
859                 throw (SSLException) e;
860             }
861             throw new SSLException("failed to initialize the client-side SSL context", e);
862         }
863     }
864 
865     static SslContext newClientContextInternal(
866             SslProvider provider,
867             Provider sslContextProvider,
868             X509Certificate[] trustCert, TrustManagerFactory trustManagerFactory,
869             X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
870             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols,
871             long sessionCacheSize, long sessionTimeout, boolean enableOcsp,
872             SecureRandom secureRandom, String keyStoreType, String endpointIdentificationAlgorithm,
873             List<SNIServerName> serverNames,
874             Map.Entry<SslContextOption<?>, Object>[] options,
875             List<OpenSslCredential> credentials) throws SSLException {
876         return newClientContextInternal(provider, sslContextProvider, trustCert, trustManagerFactory, keyCertChain, key,
877                 keyPassword, keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
878                 false, enableOcsp, secureRandom, keyStoreType, endpointIdentificationAlgorithm, serverNames, options,
879                 credentials);
880     }
881 
882     static SslContext newClientContextInternal(
883             SslProvider provider,
884             Provider sslContextProvider,
885             X509Certificate[] trustCert, TrustManagerFactory trustManagerFactory,
886             X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
887             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols,
888             long sessionCacheSize, long sessionTimeout, boolean startTls, boolean enableOcsp,
889             SecureRandom secureRandom, String keyStoreType, String endpointIdentificationAlgorithm,
890             List<SNIServerName> serverNames,
891             Map.Entry<SslContextOption<?>, Object>[] options,
892             List<OpenSslCredential> credentials) throws SSLException {
893         if (provider == null) {
894             provider = defaultClientProvider();
895         }
896 
897         ResumptionController resumptionController = new ResumptionController();
898 
899         switch (provider) {
900             case JDK:
901                 if (enableOcsp) {
902                     throw new IllegalArgumentException("OCSP is not supported with this SslProvider: " + provider);
903                 }
904                 if (credentials != null && !credentials.isEmpty()) {
905                     throw new IllegalArgumentException(
906                             "OpenSslCredential is not supported with SslProvider.JDK. " +
907                                     "Use SslProvider.OPENSSL or SslProvider.OPENSSL_REFCNT instead.");
908                 }
909                 return new JdkSslClientContext(sslContextProvider,
910                         trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
911                         keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize,
912                         sessionTimeout, secureRandom, keyStoreType, endpointIdentificationAlgorithm,
913                         serverNames, resumptionController);
914             case OPENSSL:
915                 verifyNullSslContextProvider(provider, sslContextProvider);
916                 OpenSsl.ensureAvailability();
917                 return new OpenSslClientContext(
918                         trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
919                         keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
920                         startTls, enableOcsp, keyStoreType, endpointIdentificationAlgorithm, serverNames,
921                         resumptionController, options, credentials);
922             case OPENSSL_REFCNT:
923                 verifyNullSslContextProvider(provider, sslContextProvider);
924                 OpenSsl.ensureAvailability();
925                 return new ReferenceCountedOpenSslClientContext(
926                         trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
927                         keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
928                         startTls, enableOcsp, keyStoreType, endpointIdentificationAlgorithm, serverNames,
929                         resumptionController, options, credentials);
930             default:
931                 throw new Error("Unexpected provider: " + provider);
932         }
933     }
934 
935     static ApplicationProtocolConfig toApplicationProtocolConfig(Iterable<String> nextProtocols) {
936         ApplicationProtocolConfig apn;
937         if (nextProtocols == null) {
938             apn = ApplicationProtocolConfig.DISABLED;
939         } else {
940             apn = new ApplicationProtocolConfig(
941                     Protocol.NPN_AND_ALPN, SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL,
942                     SelectedListenerFailureBehavior.ACCEPT, nextProtocols);
943         }
944         return apn;
945     }
946 
947     /**
948      * Creates a new instance (startTls set to {@code false}).
949      */
950     protected SslContext() {
951         this(false);
952     }
953 
954     /**
955      * Creates a new instance.
956      */
957     protected SslContext(boolean startTls) {
958         this(startTls, null);
959     }
960 
961     SslContext(boolean startTls, ResumptionController resumptionController) {
962         this.startTls = startTls;
963         this.resumptionController = resumptionController;
964     }
965 
966     /**
967      * Returns the {@link AttributeMap} that belongs to this {@link SslContext} .
968      */
969     public final AttributeMap attributes() {
970         return attributes;
971     }
972 
973     /**
974      * Returns {@code true} if and only if this context is for server-side.
975      */
976     public final boolean isServer() {
977         return !isClient();
978     }
979 
980     /**
981      * Returns the {@code true} if and only if this context is for client-side.
982      */
983     public abstract boolean isClient();
984 
985     /**
986      * Returns the list of enabled cipher suites, in the order of preference.
987      */
988     public abstract List<String> cipherSuites();
989 
990     /**
991      * Returns the size of the cache used for storing SSL session objects.
992      */
993     public long sessionCacheSize() {
994         return sessionContext().getSessionCacheSize();
995     }
996 
997     /**
998      * Returns the timeout for the cached SSL session objects, in seconds.
999      */
1000     public long sessionTimeout() {
1001         return sessionContext().getSessionTimeout();
1002     }
1003 
1004     /**
1005      * @deprecated Use {@link #applicationProtocolNegotiator()} instead.
1006      */
1007     @Deprecated
1008     public final List<String> nextProtocols() {
1009         return applicationProtocolNegotiator().protocols();
1010     }
1011 
1012     /**
1013      * Returns the object responsible for negotiating application layer protocols for the TLS NPN/ALPN extensions.
1014      */
1015     public abstract ApplicationProtocolNegotiator applicationProtocolNegotiator();
1016 
1017     /**
1018      * Creates a new {@link SSLEngine}.
1019      * <p>If {@link SslProvider#OPENSSL_REFCNT} is used then the object must be released. One way to do this is to
1020      * wrap in a {@link SslHandler} and insert it into a pipeline. See {@link #newHandler(ByteBufAllocator)}.
1021      * @return a new {@link SSLEngine}
1022      */
1023     public abstract SSLEngine newEngine(ByteBufAllocator alloc);
1024 
1025     /**
1026      * Creates a new {@link SSLEngine} using advisory peer information.
1027      * <p>If {@link SslProvider#OPENSSL_REFCNT} is used then the object must be released. One way to do this is to
1028      * wrap in a {@link SslHandler} and insert it into a pipeline.
1029      * See {@link #newHandler(ByteBufAllocator, String, int)}.
1030      * @param peerHost the non-authoritative name of the host
1031      * @param peerPort the non-authoritative port
1032      *
1033      * @return a new {@link SSLEngine}
1034      */
1035     public abstract SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort);
1036 
1037     /**
1038      * Returns the {@link SSLSessionContext} object held by this context.
1039      */
1040     public abstract SSLSessionContext sessionContext();
1041 
1042     /**
1043      * Create a new SslHandler.
1044      * @see #newHandler(ByteBufAllocator, Executor)
1045      */
1046     public final SslHandler newHandler(ByteBufAllocator alloc) {
1047         return newHandler(alloc, startTls);
1048     }
1049 
1050     /**
1051      * Create a new SslHandler.
1052      * @see #newHandler(ByteBufAllocator)
1053      */
1054     protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) {
1055         return new SslHandler(newEngine(alloc), startTls, ImmediateExecutor.INSTANCE, resumptionController);
1056     }
1057 
1058     /**
1059      * Creates a new {@link SslHandler}.
1060      * <p>If {@link SslProvider#OPENSSL_REFCNT} is used then the returned {@link SslHandler} will release the engine
1061      * that is wrapped. If the returned {@link SslHandler} is not inserted into a pipeline then you may leak native
1062      * memory!
1063      * <p><b>Beware</b>: the underlying generated {@link SSLEngine} won't have
1064      * <a href="https://wiki.openssl.org/index.php/Hostname_validation">hostname verification</a> enabled by default.
1065      * If you create {@link SslHandler} for the client side and want proper security, we advice that you configure
1066      * the {@link SSLEngine} (see {@link javax.net.ssl.SSLParameters#setEndpointIdentificationAlgorithm(String)}):
1067      * <pre>
1068      * SSLEngine sslEngine = sslHandler.engine();
1069      * SSLParameters sslParameters = sslEngine.getSSLParameters();
1070      * // only available since Java 7
1071      * sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
1072      * sslEngine.setSSLParameters(sslParameters);
1073      * </pre>
1074      * <p>
1075      * The underlying {@link SSLEngine} may not follow the restrictions imposed by the
1076      * <a href="https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html">SSLEngine javadocs</a> which
1077      * limits wrap/unwrap to operate on a single SSL/TLS packet.
1078      * @param alloc If supported by the SSLEngine then the SSLEngine will use this to allocate ByteBuf objects.
1079      * @param delegatedTaskExecutor the {@link Executor} that will be used to execute tasks that are returned by
1080      *                              {@link SSLEngine#getDelegatedTask()}.
1081      * @return a new {@link SslHandler}
1082      */
1083     public SslHandler newHandler(ByteBufAllocator alloc, Executor delegatedTaskExecutor) {
1084         return newHandler(alloc, startTls, delegatedTaskExecutor);
1085     }
1086 
1087     /**
1088      * Create a new SslHandler.
1089      * @see #newHandler(ByteBufAllocator, String, int, boolean, Executor)
1090      */
1091     protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls, Executor executor) {
1092         return new SslHandler(newEngine(alloc), startTls, executor, resumptionController);
1093     }
1094 
1095     /**
1096      * Creates a new {@link SslHandler}
1097      *
1098      * @see #newHandler(ByteBufAllocator, String, int, Executor)
1099      */
1100     public final SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort) {
1101         return newHandler(alloc, peerHost, peerPort, startTls);
1102     }
1103 
1104     /**
1105      * Create a new SslHandler.
1106      * @see #newHandler(ByteBufAllocator, String, int, boolean, Executor)
1107      */
1108     protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls) {
1109         return new SslHandler(newEngine(alloc, peerHost, peerPort), startTls, ImmediateExecutor.INSTANCE,
1110                 resumptionController);
1111     }
1112 
1113     /**
1114      * Creates a new {@link SslHandler} with advisory peer information.
1115      * <p>If {@link SslProvider#OPENSSL_REFCNT} is used then the returned {@link SslHandler} will release the engine
1116      * that is wrapped. If the returned {@link SslHandler} is not inserted into a pipeline then you may leak native
1117      * memory!
1118      * <p><b>Beware</b>: the underlying generated {@link SSLEngine} won't have
1119      * <a href="https://wiki.openssl.org/index.php/Hostname_validation">hostname verification</a> enabled by default.
1120      * If you create {@link SslHandler} for the client side and want proper security, we advice that you configure
1121      * the {@link SSLEngine} (see {@link javax.net.ssl.SSLParameters#setEndpointIdentificationAlgorithm(String)}):
1122      * <pre>
1123      * SSLEngine sslEngine = sslHandler.engine();
1124      * SSLParameters sslParameters = sslEngine.getSSLParameters();
1125      * // only available since Java 7
1126      * sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
1127      * sslEngine.setSSLParameters(sslParameters);
1128      * </pre>
1129      * <p>
1130      * The underlying {@link SSLEngine} may not follow the restrictions imposed by the
1131      * <a href="https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html">SSLEngine javadocs</a> which
1132      * limits wrap/unwrap to operate on a single SSL/TLS packet.
1133      * @param alloc If supported by the SSLEngine then the SSLEngine will use this to allocate ByteBuf objects.
1134      * @param peerHost the non-authoritative name of the host
1135      * @param peerPort the non-authoritative port
1136      * @param delegatedTaskExecutor the {@link Executor} that will be used to execute tasks that are returned by
1137      *                              {@link SSLEngine#getDelegatedTask()}.
1138      *
1139      * @return a new {@link SslHandler}
1140      */
1141     public SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort,
1142                                  Executor delegatedTaskExecutor) {
1143         return newHandler(alloc, peerHost, peerPort, startTls, delegatedTaskExecutor);
1144     }
1145 
1146     protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls,
1147                                     Executor delegatedTaskExecutor) {
1148         return new SslHandler(newEngine(alloc, peerHost, peerPort), startTls, delegatedTaskExecutor,
1149                 resumptionController);
1150     }
1151 
1152     /**
1153      * Generates a key specification for an (encrypted) private key.
1154      *
1155      * @param password characters, if {@code null} an unencrypted key is assumed
1156      * @param key bytes of the DER encoded private key
1157      *
1158      * @return a key specification
1159      *
1160      * @throws IOException if parsing {@code key} fails
1161      * @throws NoSuchAlgorithmException if the algorithm used to encrypt {@code key} is unknown
1162      * @throws NoSuchPaddingException if the padding scheme specified in the decryption algorithm is unknown
1163      * @throws InvalidKeySpecException if the decryption key based on {@code password} cannot be generated
1164      * @throws InvalidKeyException if the decryption key based on {@code password} cannot be used to decrypt
1165      *                             {@code key}
1166      * @throws InvalidAlgorithmParameterException if decryption algorithm parameters are somehow faulty
1167      */
1168     @Deprecated
1169     protected static PKCS8EncodedKeySpec generateKeySpec(char[] password, byte[] key)
1170             throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException,
1171             InvalidKeyException, InvalidAlgorithmParameterException {
1172 
1173         if (password == null) {
1174             return new PKCS8EncodedKeySpec(key);
1175         }
1176 
1177         EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = new EncryptedPrivateKeyInfo(key);
1178         String pbeAlgorithm = getPBEAlgorithm(encryptedPrivateKeyInfo);
1179         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(pbeAlgorithm);
1180         PBEKeySpec pbeKeySpec = new PBEKeySpec(password);
1181         SecretKey pbeKey = keyFactory.generateSecret(pbeKeySpec);
1182 
1183         Cipher cipher = Cipher.getInstance(pbeAlgorithm);
1184         cipher.init(Cipher.DECRYPT_MODE, pbeKey, encryptedPrivateKeyInfo.getAlgParameters());
1185 
1186         return encryptedPrivateKeyInfo.getKeySpec(cipher);
1187     }
1188 
1189     private static String getPBEAlgorithm(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo) {
1190         AlgorithmParameters parameters = encryptedPrivateKeyInfo.getAlgParameters();
1191         String algName = encryptedPrivateKeyInfo.getAlgName();
1192         // Java 8 ~ 16 returns OID_PKCS5_PBES2
1193         // Java 17+ returns PBES2
1194         if (parameters != null && (OID_PKCS5_PBES2.equals(algName) || PBES2.equals(algName))) {
1195             /*
1196              * This should be "PBEWith<prf>And<encryption>".
1197              * Relying on the toString() implementation is potentially
1198              * fragile but acceptable in this case since the JRE depends on
1199              * the toString() implementation as well.
1200              * In the future, if necessary, we can parse the value of
1201              * parameters.getEncoded() but the associated complexity and
1202              * unlikeliness of the JRE implementation changing means that
1203              * Tomcat will use to toString() approach for now.
1204              */
1205             return parameters.toString();
1206         }
1207         return encryptedPrivateKeyInfo.getAlgName();
1208     }
1209 
1210     /**
1211      * Generates a new {@link KeyStore}.
1212      *
1213      * @param certChain an X.509 certificate chain
1214      * @param key a PKCS#8 private key
1215      * @param keyPasswordChars the password of the {@code keyFile}.
1216      *                    {@code null} if it's not password-protected.
1217      * @param keyStoreType The KeyStore Type you want to use
1218      * @return generated {@link KeyStore}.
1219      */
1220     protected static KeyStore buildKeyStore(X509Certificate[] certChain, PrivateKey key,
1221                                   char[] keyPasswordChars, String keyStoreType)
1222             throws KeyStoreException, NoSuchAlgorithmException,
1223                    CertificateException, IOException {
1224         if (keyStoreType == null) {
1225             keyStoreType = KeyStore.getDefaultType();
1226         }
1227         KeyStore ks = KeyStore.getInstance(keyStoreType);
1228         ks.load(null, null);
1229         ks.setKeyEntry(ALIAS, key, keyPasswordChars, certChain);
1230         return ks;
1231     }
1232 
1233     protected static PrivateKey toPrivateKey(File keyFile, String keyPassword) throws NoSuchAlgorithmException,
1234                                                                 NoSuchPaddingException, InvalidKeySpecException,
1235                                                                 InvalidAlgorithmParameterException,
1236                                                                 KeyException, IOException {
1237         return toPrivateKey(keyFile, keyPassword, true);
1238     }
1239 
1240     static PrivateKey toPrivateKey(File keyFile, String keyPassword, boolean tryBouncyCastle)
1241             throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException,
1242             InvalidAlgorithmParameterException,
1243             KeyException, IOException {
1244         if (keyFile == null) {
1245             return null;
1246         }
1247 
1248         // try BC first, if this fail fallback to original key extraction process
1249         if (tryBouncyCastle && BouncyCastleUtil.isBcPkixAvailable()) {
1250             PrivateKey pk = BouncyCastlePemReader.getPrivateKey(keyFile, keyPassword);
1251             if (pk != null) {
1252                 return pk;
1253             }
1254         }
1255 
1256         return getPrivateKeyFromByteBuffer(PemReader.readPrivateKey(keyFile), keyPassword);
1257     }
1258 
1259     protected static PrivateKey toPrivateKey(InputStream keyInputStream, String keyPassword)
1260                                                                 throws NoSuchAlgorithmException,
1261                                                                 NoSuchPaddingException, InvalidKeySpecException,
1262                                                                 InvalidAlgorithmParameterException,
1263                                                                 KeyException, IOException {
1264         if (keyInputStream == null) {
1265             return null;
1266         }
1267 
1268         // try BC first, if this fail fallback to original key extraction process
1269         if (BouncyCastleUtil.isBcPkixAvailable()) {
1270             if (!keyInputStream.markSupported()) {
1271                 // We need an input stream that supports resetting, in case BouncyCastle fails to read.
1272                 keyInputStream = new BufferedInputStream(keyInputStream);
1273             }
1274             keyInputStream.mark(1048576); // Be able to reset up to 1 MiB of data.
1275             PrivateKey pk = BouncyCastlePemReader.getPrivateKey(keyInputStream, keyPassword);
1276             if (pk != null) {
1277                 return pk;
1278             }
1279             // BouncyCastle could not read the key. Reset the input stream in case the input position changed.
1280             keyInputStream.reset();
1281         }
1282 
1283         return getPrivateKeyFromByteBuffer(PemReader.readPrivateKey(keyInputStream), keyPassword);
1284     }
1285 
1286     private static PrivateKey getPrivateKeyFromByteBuffer(ByteBuf encodedKeyBuf, String keyPassword)
1287             throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException,
1288             InvalidAlgorithmParameterException, KeyException, IOException {
1289 
1290         byte[] encodedKey = new byte[encodedKeyBuf.readableBytes()];
1291         encodedKeyBuf.readBytes(encodedKey).release();
1292 
1293         PKCS8EncodedKeySpec encodedKeySpec = generateKeySpec(
1294                 keyPassword == null ? null : keyPassword.toCharArray(), encodedKey);
1295         try {
1296             return KeyFactory.getInstance("RSA").generatePrivate(encodedKeySpec);
1297         } catch (InvalidKeySpecException ignore) {
1298             try {
1299                 return KeyFactory.getInstance("DSA").generatePrivate(encodedKeySpec);
1300             } catch (InvalidKeySpecException ignore2) {
1301                 try {
1302                     return KeyFactory.getInstance("EC").generatePrivate(encodedKeySpec);
1303                 } catch (InvalidKeySpecException e) {
1304                     throw new InvalidKeySpecException("Neither RSA, DSA nor EC worked", e);
1305                 }
1306             }
1307         }
1308     }
1309 
1310     /**
1311      * Build a {@link TrustManagerFactory} from a certificate chain file.
1312      * @param certChainFile The certificate file to build from.
1313      * @param trustManagerFactory The existing {@link TrustManagerFactory} that will be used if not {@code null}.
1314      * @return A {@link TrustManagerFactory} which contains the certificates in {@code certChainFile}
1315      */
1316     @Deprecated
1317     protected static TrustManagerFactory buildTrustManagerFactory(
1318             File certChainFile, TrustManagerFactory trustManagerFactory)
1319             throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
1320         return buildTrustManagerFactory(certChainFile, trustManagerFactory, null);
1321     }
1322 
1323     /**
1324      * Build a {@link TrustManagerFactory} from a certificate chain file.
1325      * @param certChainFile The certificate file to build from.
1326      * @param trustManagerFactory The existing {@link TrustManagerFactory} that will be used if not {@code null}.
1327      * @param keyType The KeyStore Type you want to use
1328      * @return A {@link TrustManagerFactory} which contains the certificates in {@code certChainFile}
1329      */
1330     protected static TrustManagerFactory buildTrustManagerFactory(
1331             File certChainFile, TrustManagerFactory trustManagerFactory, String keyType)
1332             throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
1333         X509Certificate[] x509Certs = toX509Certificates(certChainFile);
1334 
1335         return buildTrustManagerFactory(x509Certs, trustManagerFactory, keyType);
1336     }
1337 
1338     protected static X509Certificate[] toX509Certificates(File file) throws CertificateException {
1339         if (file == null) {
1340             return null;
1341         }
1342         return getCertificatesFromBuffers(PemReader.readCertificates(file));
1343     }
1344 
1345     protected static X509Certificate[] toX509Certificates(InputStream in) throws CertificateException {
1346         if (in == null) {
1347             return null;
1348         }
1349         return getCertificatesFromBuffers(PemReader.readCertificates(in));
1350     }
1351 
1352     private static X509Certificate[] getCertificatesFromBuffers(ByteBuf[] certs) throws CertificateException {
1353         CertificateFactory cf = CertificateFactory.getInstance("X.509");
1354         X509Certificate[] x509Certs = new X509Certificate[certs.length];
1355 
1356         try {
1357             for (int i = 0; i < certs.length; i++) {
1358                 try (InputStream is = new ByteBufInputStream(certs[i], false)) {
1359                     x509Certs[i] = (X509Certificate) cf.generateCertificate(is);
1360                 } catch (IOException e) {
1361                     // This is not expected to happen, but re-throw in case it does.
1362                     throw new RuntimeException(e);
1363                 }
1364             }
1365         } finally {
1366             for (ByteBuf buf: certs) {
1367                 buf.release();
1368             }
1369         }
1370         return x509Certs;
1371     }
1372 
1373     protected static TrustManagerFactory buildTrustManagerFactory(
1374             X509Certificate[] certCollection, TrustManagerFactory trustManagerFactory, String keyStoreType)
1375             throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
1376         if (keyStoreType == null) {
1377             keyStoreType = KeyStore.getDefaultType();
1378         }
1379         final KeyStore ks = KeyStore.getInstance(keyStoreType);
1380         ks.load(null, null);
1381 
1382         int i = 1;
1383         for (X509Certificate cert: certCollection) {
1384             String alias = Integer.toString(i);
1385             ks.setCertificateEntry(alias, cert);
1386             i++;
1387         }
1388 
1389         // Set up trust manager factory to use our key store.
1390         if (trustManagerFactory == null) {
1391             trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
1392         }
1393         trustManagerFactory.init(ks);
1394 
1395         return trustManagerFactory;
1396     }
1397 
1398     static PrivateKey toPrivateKeyInternal(File keyFile, String keyPassword) throws SSLException {
1399         try {
1400             return toPrivateKey(keyFile, keyPassword);
1401         } catch (Exception e) {
1402             throw new SSLException(e);
1403         }
1404     }
1405 
1406     static X509Certificate[] toX509CertificatesInternal(File file) throws SSLException {
1407         try {
1408             return toX509Certificates(file);
1409         } catch (CertificateException e) {
1410             throw new SSLException(e);
1411         }
1412     }
1413 
1414     protected static KeyManagerFactory buildKeyManagerFactory(X509Certificate[] certChainFile,
1415                                                     String keyAlgorithm, PrivateKey key,
1416                                                     String keyPassword, KeyManagerFactory kmf,
1417                                                     String keyStore)
1418             throws KeyStoreException, NoSuchAlgorithmException, IOException,
1419             CertificateException, UnrecoverableKeyException {
1420         if (keyAlgorithm == null) {
1421             keyAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
1422         }
1423         char[] keyPasswordChars = keyStorePassword(keyPassword);
1424         KeyStore ks = buildKeyStore(certChainFile, key, keyPasswordChars, keyStore);
1425         return buildKeyManagerFactory(ks, keyAlgorithm, keyPasswordChars, kmf);
1426     }
1427 
1428     static KeyManagerFactory buildKeyManagerFactory(KeyStore ks,
1429                                                     String keyAlgorithm,
1430                                                     char[] keyPasswordChars, KeyManagerFactory kmf)
1431             throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
1432         // Set up key manager factory to use our key store
1433         if (kmf == null) {
1434             if (keyAlgorithm == null) {
1435                 keyAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
1436             }
1437             kmf = KeyManagerFactory.getInstance(keyAlgorithm);
1438         }
1439         kmf.init(ks, keyPasswordChars);
1440 
1441         return kmf;
1442     }
1443 
1444     static char[] keyStorePassword(String keyPassword) {
1445         return keyPassword == null ? EmptyArrays.EMPTY_CHARS : keyPassword.toCharArray();
1446     }
1447 }