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