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