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