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