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