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