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