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