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