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