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