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