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  import io.netty.util.internal.PlatformDependent;
32  
33  import java.io.BufferedInputStream;
34  import java.security.Provider;
35  import javax.net.ssl.KeyManager;
36  import javax.net.ssl.KeyManagerFactory;
37  import javax.crypto.Cipher;
38  import javax.crypto.EncryptedPrivateKeyInfo;
39  import javax.crypto.NoSuchPaddingException;
40  import javax.crypto.SecretKey;
41  import javax.crypto.SecretKeyFactory;
42  import javax.crypto.spec.PBEKeySpec;
43  import javax.net.ssl.SSLContext;
44  import javax.net.ssl.SSLEngine;
45  import javax.net.ssl.SSLException;
46  import javax.net.ssl.SSLSessionContext;
47  import javax.net.ssl.TrustManager;
48  import javax.net.ssl.TrustManagerFactory;
49  
50  import java.io.File;
51  import java.io.IOException;
52  import java.io.InputStream;
53  import java.security.AlgorithmParameters;
54  import java.security.InvalidAlgorithmParameterException;
55  import java.security.InvalidKeyException;
56  import java.security.KeyException;
57  import java.security.KeyFactory;
58  import java.security.KeyStore;
59  import java.security.KeyStoreException;
60  import java.security.NoSuchAlgorithmException;
61  import java.security.PrivateKey;
62  import java.security.SecureRandom;
63  import java.security.UnrecoverableKeyException;
64  import java.security.cert.CertificateException;
65  import java.security.cert.CertificateFactory;
66  import java.security.cert.X509Certificate;
67  import java.security.spec.InvalidKeySpecException;
68  import java.security.spec.PKCS8EncodedKeySpec;
69  import java.util.List;
70  import java.util.Map;
71  import java.util.concurrent.Executor;
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(), null);
811         } catch (Exception e) {
812             if (e instanceof SSLException) {
813                 throw (SSLException) e;
814             }
815             throw new SSLException("failed to initialize the client-side SSL context", e);
816         }
817     }
818 
819     static SslContext newClientContextInternal(
820             SslProvider provider,
821             Provider sslContextProvider,
822             X509Certificate[] trustCert, TrustManagerFactory trustManagerFactory,
823             X509Certificate[] keyCertChain, PrivateKey key, String keyPassword, KeyManagerFactory keyManagerFactory,
824             Iterable<String> ciphers, CipherSuiteFilter cipherFilter, ApplicationProtocolConfig apn, String[] protocols,
825             long sessionCacheSize, long sessionTimeout, boolean enableOcsp,
826             SecureRandom secureRandom, String keyStoreType, String endpointIdentificationAlgorithm,
827             Map.Entry<SslContextOption<?>, Object>... options) throws SSLException {
828         if (provider == null) {
829             provider = defaultClientProvider();
830         }
831 
832         ResumptionController resumptionController = new ResumptionController();
833 
834         switch (provider) {
835             case JDK:
836                 if (enableOcsp) {
837                     throw new IllegalArgumentException("OCSP is not supported with this SslProvider: " + provider);
838                 }
839                 return new JdkSslClientContext(sslContextProvider,
840                         trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
841                         keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize,
842                         sessionTimeout, secureRandom, keyStoreType, endpointIdentificationAlgorithm,
843                         resumptionController);
844             case OPENSSL:
845                 verifyNullSslContextProvider(provider, sslContextProvider);
846                 OpenSsl.ensureAvailability();
847                 return new OpenSslClientContext(
848                         trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
849                         keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
850                         enableOcsp, keyStoreType, endpointIdentificationAlgorithm, resumptionController, options);
851             case OPENSSL_REFCNT:
852                 verifyNullSslContextProvider(provider, sslContextProvider);
853                 OpenSsl.ensureAvailability();
854                 return new ReferenceCountedOpenSslClientContext(
855                         trustCert, trustManagerFactory, keyCertChain, key, keyPassword,
856                         keyManagerFactory, ciphers, cipherFilter, apn, protocols, sessionCacheSize, sessionTimeout,
857                         enableOcsp, keyStoreType, endpointIdentificationAlgorithm, resumptionController, options);
858             default:
859                 throw new Error(provider.toString());
860         }
861     }
862 
863     static ApplicationProtocolConfig toApplicationProtocolConfig(Iterable<String> nextProtocols) {
864         ApplicationProtocolConfig apn;
865         if (nextProtocols == null) {
866             apn = ApplicationProtocolConfig.DISABLED;
867         } else {
868             apn = new ApplicationProtocolConfig(
869                     Protocol.NPN_AND_ALPN, SelectorFailureBehavior.CHOOSE_MY_LAST_PROTOCOL,
870                     SelectedListenerFailureBehavior.ACCEPT, nextProtocols);
871         }
872         return apn;
873     }
874 
875     /**
876      * Creates a new instance (startTls set to {@code false}).
877      */
878     protected SslContext() {
879         this(false);
880     }
881 
882     /**
883      * Creates a new instance.
884      */
885     protected SslContext(boolean startTls) {
886         this(startTls, null);
887     }
888 
889     SslContext(boolean startTls, ResumptionController resumptionController) {
890         this.startTls = startTls;
891         this.resumptionController = resumptionController;
892     }
893 
894     /**
895      * Returns the {@link AttributeMap} that belongs to this {@link SslContext} .
896      */
897     public final AttributeMap attributes() {
898         return attributes;
899     }
900 
901     /**
902      * Returns {@code true} if and only if this context is for server-side.
903      */
904     public final boolean isServer() {
905         return !isClient();
906     }
907 
908     /**
909      * Returns the {@code true} if and only if this context is for client-side.
910      */
911     public abstract boolean isClient();
912 
913     /**
914      * Returns the list of enabled cipher suites, in the order of preference.
915      */
916     public abstract List<String> cipherSuites();
917 
918     /**
919      * Returns the size of the cache used for storing SSL session objects.
920      */
921     public long sessionCacheSize() {
922         return sessionContext().getSessionCacheSize();
923     }
924 
925     /**
926      * Returns the timeout for the cached SSL session objects, in seconds.
927      */
928     public long sessionTimeout() {
929         return sessionContext().getSessionTimeout();
930     }
931 
932     /**
933      * @deprecated Use {@link #applicationProtocolNegotiator()} instead.
934      */
935     @Deprecated
936     public final List<String> nextProtocols() {
937         return applicationProtocolNegotiator().protocols();
938     }
939 
940     /**
941      * Returns the object responsible for negotiating application layer protocols for the TLS NPN/ALPN extensions.
942      */
943     public abstract ApplicationProtocolNegotiator applicationProtocolNegotiator();
944 
945     /**
946      * Creates a new {@link SSLEngine}.
947      * <p>If {@link SslProvider#OPENSSL_REFCNT} is used then the object must be released. One way to do this is to
948      * wrap in a {@link SslHandler} and insert it into a pipeline. See {@link #newHandler(ByteBufAllocator)}.
949      * @return a new {@link SSLEngine}
950      */
951     public abstract SSLEngine newEngine(ByteBufAllocator alloc);
952 
953     /**
954      * Creates a new {@link SSLEngine} using advisory peer information.
955      * <p>If {@link SslProvider#OPENSSL_REFCNT} is used then the object must be released. One way to do this is to
956      * wrap in a {@link SslHandler} and insert it into a pipeline.
957      * See {@link #newHandler(ByteBufAllocator, String, int)}.
958      * @param peerHost the non-authoritative name of the host
959      * @param peerPort the non-authoritative port
960      *
961      * @return a new {@link SSLEngine}
962      */
963     public abstract SSLEngine newEngine(ByteBufAllocator alloc, String peerHost, int peerPort);
964 
965     /**
966      * Returns the {@link SSLSessionContext} object held by this context.
967      */
968     public abstract SSLSessionContext sessionContext();
969 
970     /**
971      * Create a new SslHandler.
972      * @see #newHandler(ByteBufAllocator, Executor)
973      */
974     public final SslHandler newHandler(ByteBufAllocator alloc) {
975         return newHandler(alloc, startTls);
976     }
977 
978     /**
979      * Create a new SslHandler.
980      * @see #newHandler(ByteBufAllocator)
981      */
982     protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls) {
983         return new SslHandler(newEngine(alloc), startTls, ImmediateExecutor.INSTANCE, resumptionController);
984     }
985 
986     /**
987      * Creates a new {@link SslHandler}.
988      * <p>If {@link SslProvider#OPENSSL_REFCNT} is used then the returned {@link SslHandler} will release the engine
989      * that is wrapped. If the returned {@link SslHandler} is not inserted into a pipeline then you may leak native
990      * memory!
991      * <p><b>Beware</b>: the underlying generated {@link SSLEngine} won't have
992      * <a href="https://wiki.openssl.org/index.php/Hostname_validation">hostname verification</a> enabled by default.
993      * If you create {@link SslHandler} for the client side and want proper security, we advice that you configure
994      * the {@link SSLEngine} (see {@link javax.net.ssl.SSLParameters#setEndpointIdentificationAlgorithm(String)}):
995      * <pre>
996      * SSLEngine sslEngine = sslHandler.engine();
997      * SSLParameters sslParameters = sslEngine.getSSLParameters();
998      * // only available since Java 7
999      * sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
1000      * sslEngine.setSSLParameters(sslParameters);
1001      * </pre>
1002      * <p>
1003      * The underlying {@link SSLEngine} may not follow the restrictions imposed by the
1004      * <a href="https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html">SSLEngine javadocs</a> which
1005      * limits wrap/unwrap to operate on a single SSL/TLS packet.
1006      * @param alloc If supported by the SSLEngine then the SSLEngine will use this to allocate ByteBuf objects.
1007      * @param delegatedTaskExecutor the {@link Executor} that will be used to execute tasks that are returned by
1008      *                              {@link SSLEngine#getDelegatedTask()}.
1009      * @return a new {@link SslHandler}
1010      */
1011     public SslHandler newHandler(ByteBufAllocator alloc, Executor delegatedTaskExecutor) {
1012         return newHandler(alloc, startTls, delegatedTaskExecutor);
1013     }
1014 
1015     /**
1016      * Create a new SslHandler.
1017      * @see #newHandler(ByteBufAllocator, String, int, boolean, Executor)
1018      */
1019     protected SslHandler newHandler(ByteBufAllocator alloc, boolean startTls, Executor executor) {
1020         return new SslHandler(newEngine(alloc), startTls, executor, resumptionController);
1021     }
1022 
1023     /**
1024      * Creates a new {@link SslHandler}
1025      *
1026      * @see #newHandler(ByteBufAllocator, String, int, Executor)
1027      */
1028     public final SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort) {
1029         return newHandler(alloc, peerHost, peerPort, startTls);
1030     }
1031 
1032     /**
1033      * Create a new SslHandler.
1034      * @see #newHandler(ByteBufAllocator, String, int, boolean, Executor)
1035      */
1036     protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls) {
1037         return new SslHandler(newEngine(alloc, peerHost, peerPort), startTls, ImmediateExecutor.INSTANCE,
1038                 resumptionController);
1039     }
1040 
1041     /**
1042      * Creates a new {@link SslHandler} with advisory peer information.
1043      * <p>If {@link SslProvider#OPENSSL_REFCNT} is used then the returned {@link SslHandler} will release the engine
1044      * that is wrapped. If the returned {@link SslHandler} is not inserted into a pipeline then you may leak native
1045      * memory!
1046      * <p><b>Beware</b>: the underlying generated {@link SSLEngine} won't have
1047      * <a href="https://wiki.openssl.org/index.php/Hostname_validation">hostname verification</a> enabled by default.
1048      * If you create {@link SslHandler} for the client side and want proper security, we advice that you configure
1049      * the {@link SSLEngine} (see {@link javax.net.ssl.SSLParameters#setEndpointIdentificationAlgorithm(String)}):
1050      * <pre>
1051      * SSLEngine sslEngine = sslHandler.engine();
1052      * SSLParameters sslParameters = sslEngine.getSSLParameters();
1053      * // only available since Java 7
1054      * sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
1055      * sslEngine.setSSLParameters(sslParameters);
1056      * </pre>
1057      * <p>
1058      * The underlying {@link SSLEngine} may not follow the restrictions imposed by the
1059      * <a href="https://docs.oracle.com/javase/7/docs/api/javax/net/ssl/SSLEngine.html">SSLEngine javadocs</a> which
1060      * limits wrap/unwrap to operate on a single SSL/TLS packet.
1061      * @param alloc If supported by the SSLEngine then the SSLEngine will use this to allocate ByteBuf objects.
1062      * @param peerHost the non-authoritative name of the host
1063      * @param peerPort the non-authoritative port
1064      * @param delegatedTaskExecutor the {@link Executor} that will be used to execute tasks that are returned by
1065      *                              {@link SSLEngine#getDelegatedTask()}.
1066      *
1067      * @return a new {@link SslHandler}
1068      */
1069     public SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort,
1070                                  Executor delegatedTaskExecutor) {
1071         return newHandler(alloc, peerHost, peerPort, startTls, delegatedTaskExecutor);
1072     }
1073 
1074     protected SslHandler newHandler(ByteBufAllocator alloc, String peerHost, int peerPort, boolean startTls,
1075                                     Executor delegatedTaskExecutor) {
1076         return new SslHandler(newEngine(alloc, peerHost, peerPort), startTls, delegatedTaskExecutor,
1077                 resumptionController);
1078     }
1079 
1080     /**
1081      * Generates a key specification for an (encrypted) private key.
1082      *
1083      * @param password characters, if {@code null} an unencrypted key is assumed
1084      * @param key bytes of the DER encoded private key
1085      *
1086      * @return a key specification
1087      *
1088      * @throws IOException if parsing {@code key} fails
1089      * @throws NoSuchAlgorithmException if the algorithm used to encrypt {@code key} is unknown
1090      * @throws NoSuchPaddingException if the padding scheme specified in the decryption algorithm is unknown
1091      * @throws InvalidKeySpecException if the decryption key based on {@code password} cannot be generated
1092      * @throws InvalidKeyException if the decryption key based on {@code password} cannot be used to decrypt
1093      *                             {@code key}
1094      * @throws InvalidAlgorithmParameterException if decryption algorithm parameters are somehow faulty
1095      */
1096     @Deprecated
1097     protected static PKCS8EncodedKeySpec generateKeySpec(char[] password, byte[] key)
1098             throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException,
1099             InvalidKeyException, InvalidAlgorithmParameterException {
1100 
1101         if (password == null) {
1102             return new PKCS8EncodedKeySpec(key);
1103         }
1104 
1105         EncryptedPrivateKeyInfo encryptedPrivateKeyInfo = new EncryptedPrivateKeyInfo(key);
1106         String pbeAlgorithm = getPBEAlgorithm(encryptedPrivateKeyInfo);
1107         SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(pbeAlgorithm);
1108         PBEKeySpec pbeKeySpec = new PBEKeySpec(password);
1109         SecretKey pbeKey = keyFactory.generateSecret(pbeKeySpec);
1110 
1111         Cipher cipher = Cipher.getInstance(pbeAlgorithm);
1112         cipher.init(Cipher.DECRYPT_MODE, pbeKey, encryptedPrivateKeyInfo.getAlgParameters());
1113 
1114         return encryptedPrivateKeyInfo.getKeySpec(cipher);
1115     }
1116 
1117     private static String getPBEAlgorithm(EncryptedPrivateKeyInfo encryptedPrivateKeyInfo) {
1118         AlgorithmParameters parameters = encryptedPrivateKeyInfo.getAlgParameters();
1119         String algName = encryptedPrivateKeyInfo.getAlgName();
1120         // Java 8 ~ 16 returns OID_PKCS5_PBES2
1121         // Java 17+ returns PBES2
1122         if (PlatformDependent.javaVersion() >= 8 && parameters != null &&
1123                 (OID_PKCS5_PBES2.equals(algName) || PBES2.equals(algName))) {
1124             /*
1125              * This should be "PBEWith<prf>And<encryption>".
1126              * Relying on the toString() implementation is potentially
1127              * fragile but acceptable in this case since the JRE depends on
1128              * the toString() implementation as well.
1129              * In the future, if necessary, we can parse the value of
1130              * parameters.getEncoded() but the associated complexity and
1131              * unlikeliness of the JRE implementation changing means that
1132              * Tomcat will use to toString() approach for now.
1133              */
1134             return parameters.toString();
1135         }
1136         return encryptedPrivateKeyInfo.getAlgName();
1137     }
1138 
1139     /**
1140      * Generates a new {@link KeyStore}.
1141      *
1142      * @param certChain an X.509 certificate chain
1143      * @param key a PKCS#8 private key
1144      * @param keyPasswordChars the password of the {@code keyFile}.
1145      *                    {@code null} if it's not password-protected.
1146      * @param keyStoreType The KeyStore Type you want to use
1147      * @return generated {@link KeyStore}.
1148      */
1149     protected static KeyStore buildKeyStore(X509Certificate[] certChain, PrivateKey key,
1150                                   char[] keyPasswordChars, String keyStoreType)
1151             throws KeyStoreException, NoSuchAlgorithmException,
1152                    CertificateException, IOException {
1153         if (keyStoreType == null) {
1154             keyStoreType = KeyStore.getDefaultType();
1155         }
1156         KeyStore ks = KeyStore.getInstance(keyStoreType);
1157         ks.load(null, null);
1158         ks.setKeyEntry(ALIAS, key, keyPasswordChars, certChain);
1159         return ks;
1160     }
1161 
1162     protected static PrivateKey toPrivateKey(File keyFile, String keyPassword) throws NoSuchAlgorithmException,
1163                                                                 NoSuchPaddingException, InvalidKeySpecException,
1164                                                                 InvalidAlgorithmParameterException,
1165                                                                 KeyException, IOException {
1166         return toPrivateKey(keyFile, keyPassword, true);
1167     }
1168 
1169     static PrivateKey toPrivateKey(File keyFile, String keyPassword, boolean tryBouncyCastle)
1170             throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException,
1171             InvalidAlgorithmParameterException,
1172             KeyException, IOException {
1173         if (keyFile == null) {
1174             return null;
1175         }
1176 
1177         // try BC first, if this fail fallback to original key extraction process
1178         if (tryBouncyCastle && BouncyCastlePemReader.isAvailable()) {
1179             PrivateKey pk = BouncyCastlePemReader.getPrivateKey(keyFile, keyPassword);
1180             if (pk != null) {
1181                 return pk;
1182             }
1183         }
1184 
1185         return getPrivateKeyFromByteBuffer(PemReader.readPrivateKey(keyFile), keyPassword);
1186     }
1187 
1188     protected static PrivateKey toPrivateKey(InputStream keyInputStream, String keyPassword)
1189                                                                 throws NoSuchAlgorithmException,
1190                                                                 NoSuchPaddingException, InvalidKeySpecException,
1191                                                                 InvalidAlgorithmParameterException,
1192                                                                 KeyException, IOException {
1193         if (keyInputStream == null) {
1194             return null;
1195         }
1196 
1197         // try BC first, if this fail fallback to original key extraction process
1198         if (BouncyCastlePemReader.isAvailable()) {
1199             if (!keyInputStream.markSupported()) {
1200                 // We need an input stream that supports resetting, in case BouncyCastle fails to read.
1201                 keyInputStream = new BufferedInputStream(keyInputStream);
1202             }
1203             keyInputStream.mark(1048576); // Be able to reset up to 1 MiB of data.
1204             PrivateKey pk = BouncyCastlePemReader.getPrivateKey(keyInputStream, keyPassword);
1205             if (pk != null) {
1206                 return pk;
1207             }
1208             // BouncyCastle could not read the key. Reset the input stream in case the input position changed.
1209             keyInputStream.reset();
1210         }
1211 
1212         return getPrivateKeyFromByteBuffer(PemReader.readPrivateKey(keyInputStream), keyPassword);
1213     }
1214 
1215     private static PrivateKey getPrivateKeyFromByteBuffer(ByteBuf encodedKeyBuf, String keyPassword)
1216             throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException,
1217             InvalidAlgorithmParameterException, KeyException, IOException {
1218 
1219         byte[] encodedKey = new byte[encodedKeyBuf.readableBytes()];
1220         encodedKeyBuf.readBytes(encodedKey).release();
1221 
1222         PKCS8EncodedKeySpec encodedKeySpec = generateKeySpec(
1223                 keyPassword == null ? null : keyPassword.toCharArray(), encodedKey);
1224         try {
1225             return KeyFactory.getInstance("RSA").generatePrivate(encodedKeySpec);
1226         } catch (InvalidKeySpecException ignore) {
1227             try {
1228                 return KeyFactory.getInstance("DSA").generatePrivate(encodedKeySpec);
1229             } catch (InvalidKeySpecException ignore2) {
1230                 try {
1231                     return KeyFactory.getInstance("EC").generatePrivate(encodedKeySpec);
1232                 } catch (InvalidKeySpecException e) {
1233                     throw new InvalidKeySpecException("Neither RSA, DSA nor EC worked", e);
1234                 }
1235             }
1236         }
1237     }
1238 
1239     /**
1240      * Build a {@link TrustManagerFactory} from a certificate chain file.
1241      * @param certChainFile The certificate file to build from.
1242      * @param trustManagerFactory The existing {@link TrustManagerFactory} that will be used if not {@code null}.
1243      * @return A {@link TrustManagerFactory} which contains the certificates in {@code certChainFile}
1244      */
1245     @Deprecated
1246     protected static TrustManagerFactory buildTrustManagerFactory(
1247             File certChainFile, TrustManagerFactory trustManagerFactory)
1248             throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
1249         return buildTrustManagerFactory(certChainFile, trustManagerFactory, null);
1250     }
1251 
1252     /**
1253      * Build a {@link TrustManagerFactory} from a certificate chain file.
1254      * @param certChainFile The certificate file to build from.
1255      * @param trustManagerFactory The existing {@link TrustManagerFactory} that will be used if not {@code null}.
1256      * @param keyType The KeyStore Type you want to use
1257      * @return A {@link TrustManagerFactory} which contains the certificates in {@code certChainFile}
1258      */
1259     protected static TrustManagerFactory buildTrustManagerFactory(
1260             File certChainFile, TrustManagerFactory trustManagerFactory, String keyType)
1261             throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
1262         X509Certificate[] x509Certs = toX509Certificates(certChainFile);
1263 
1264         return buildTrustManagerFactory(x509Certs, trustManagerFactory, keyType);
1265     }
1266 
1267     protected static X509Certificate[] toX509Certificates(File file) throws CertificateException {
1268         if (file == null) {
1269             return null;
1270         }
1271         return getCertificatesFromBuffers(PemReader.readCertificates(file));
1272     }
1273 
1274     protected static X509Certificate[] toX509Certificates(InputStream in) throws CertificateException {
1275         if (in == null) {
1276             return null;
1277         }
1278         return getCertificatesFromBuffers(PemReader.readCertificates(in));
1279     }
1280 
1281     private static X509Certificate[] getCertificatesFromBuffers(ByteBuf[] certs) throws CertificateException {
1282         CertificateFactory cf = CertificateFactory.getInstance("X.509");
1283         X509Certificate[] x509Certs = new X509Certificate[certs.length];
1284 
1285         try {
1286             for (int i = 0; i < certs.length; i++) {
1287                 InputStream is = new ByteBufInputStream(certs[i], false);
1288                 try {
1289                     x509Certs[i] = (X509Certificate) cf.generateCertificate(is);
1290                 } finally {
1291                     try {
1292                         is.close();
1293                     } catch (IOException e) {
1294                         // This is not expected to happen, but re-throw in case it does.
1295                         throw new RuntimeException(e);
1296                     }
1297                 }
1298             }
1299         } finally {
1300             for (ByteBuf buf: certs) {
1301                 buf.release();
1302             }
1303         }
1304         return x509Certs;
1305     }
1306 
1307     protected static TrustManagerFactory buildTrustManagerFactory(
1308             X509Certificate[] certCollection, TrustManagerFactory trustManagerFactory, String keyStoreType)
1309             throws NoSuchAlgorithmException, CertificateException, KeyStoreException, IOException {
1310         if (keyStoreType == null) {
1311             keyStoreType = KeyStore.getDefaultType();
1312         }
1313         final KeyStore ks = KeyStore.getInstance(keyStoreType);
1314         ks.load(null, null);
1315 
1316         int i = 1;
1317         for (X509Certificate cert: certCollection) {
1318             String alias = Integer.toString(i);
1319             ks.setCertificateEntry(alias, cert);
1320             i++;
1321         }
1322 
1323         // Set up trust manager factory to use our key store.
1324         if (trustManagerFactory == null) {
1325             trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
1326         }
1327         trustManagerFactory.init(ks);
1328 
1329         return trustManagerFactory;
1330     }
1331 
1332     static PrivateKey toPrivateKeyInternal(File keyFile, String keyPassword) throws SSLException {
1333         try {
1334             return toPrivateKey(keyFile, keyPassword);
1335         } catch (Exception e) {
1336             throw new SSLException(e);
1337         }
1338     }
1339 
1340     static X509Certificate[] toX509CertificatesInternal(File file) throws SSLException {
1341         try {
1342             return toX509Certificates(file);
1343         } catch (CertificateException e) {
1344             throw new SSLException(e);
1345         }
1346     }
1347 
1348     protected static KeyManagerFactory buildKeyManagerFactory(X509Certificate[] certChainFile,
1349                                                     String keyAlgorithm, PrivateKey key,
1350                                                     String keyPassword, KeyManagerFactory kmf,
1351                                                     String keyStore)
1352             throws KeyStoreException, NoSuchAlgorithmException, IOException,
1353             CertificateException, UnrecoverableKeyException {
1354         if (keyAlgorithm == null) {
1355             keyAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
1356         }
1357         char[] keyPasswordChars = keyStorePassword(keyPassword);
1358         KeyStore ks = buildKeyStore(certChainFile, key, keyPasswordChars, keyStore);
1359         return buildKeyManagerFactory(ks, keyAlgorithm, keyPasswordChars, kmf);
1360     }
1361 
1362     static KeyManagerFactory buildKeyManagerFactory(KeyStore ks,
1363                                                     String keyAlgorithm,
1364                                                     char[] keyPasswordChars, KeyManagerFactory kmf)
1365             throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
1366         // Set up key manager factory to use our key store
1367         if (kmf == null) {
1368             if (keyAlgorithm == null) {
1369                 keyAlgorithm = KeyManagerFactory.getDefaultAlgorithm();
1370             }
1371             kmf = KeyManagerFactory.getInstance(keyAlgorithm);
1372         }
1373         kmf.init(ks, keyPasswordChars);
1374 
1375         return kmf;
1376     }
1377 
1378     static char[] keyStorePassword(String keyPassword) {
1379         return keyPassword == null ? EmptyArrays.EMPTY_CHARS : keyPassword.toCharArray();
1380     }
1381 }