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