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