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