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