1 // ========================================================================
2 // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3 // ------------------------------------------------------------------------
4 // All rights reserved. This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v1.0
6 // and Apache License v2.0 which accompanies this distribution.
7 // The Eclipse Public License is available at
8 // http://www.eclipse.org/legal/epl-v10.html
9 // The Apache License v2.0 is available at
10 // http://www.opensource.org/licenses/apache2.0.php
11 // You may elect to redistribute this code under either of these licenses.
12 // ========================================================================
13
14 package org.eclipse.jetty.server.ssl;
15
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.nio.channels.SelectionKey;
19 import java.nio.channels.SocketChannel;
20 import java.security.KeyStore;
21 import java.security.SecureRandom;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.List;
25
26 import javax.net.ssl.KeyManager;
27 import javax.net.ssl.KeyManagerFactory;
28 import javax.net.ssl.SSLContext;
29 import javax.net.ssl.SSLEngine;
30 import javax.net.ssl.SSLSession;
31 import javax.net.ssl.SSLSocket;
32 import javax.net.ssl.TrustManager;
33 import javax.net.ssl.TrustManagerFactory;
34
35 import org.eclipse.jetty.http.HttpParser;
36 import org.eclipse.jetty.http.HttpSchemes;
37 import org.eclipse.jetty.http.security.Password;
38 import org.eclipse.jetty.io.Buffer;
39 import org.eclipse.jetty.io.Buffers;
40 import org.eclipse.jetty.io.Connection;
41 import org.eclipse.jetty.io.EndPoint;
42 import org.eclipse.jetty.io.ThreadLocalBuffers;
43 import org.eclipse.jetty.io.bio.SocketEndPoint;
44 import org.eclipse.jetty.io.nio.DirectNIOBuffer;
45 import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
46 import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint;
47 import org.eclipse.jetty.io.nio.SelectorManager.SelectSet;
48 import org.eclipse.jetty.server.HttpConnection;
49 import org.eclipse.jetty.server.Request;
50 import org.eclipse.jetty.server.nio.SelectChannelConnector;
51 import org.eclipse.jetty.util.log.Log;
52 import org.eclipse.jetty.util.resource.Resource;
53
54 /* ------------------------------------------------------------ */
55 /**
56 * SslSelectChannelConnector.
57 *
58 * @org.apache.xbean.XBean element="sslConnector" description="Creates an NIO ssl connector"
59 *
60 *
61 *
62 */
63 public class SslSelectChannelConnector extends SelectChannelConnector implements SslConnector
64 {
65 /** Default value for the excluded cipher Suites. */
66 private String _excludeCipherSuites[]=null;
67 /** Default value for the included cipher Suites. */
68 private String _includeCipherSuites[]=null;
69
70 /** Default value for the keystore location path. */
71 private String _keystorePath=DEFAULT_KEYSTORE;
72 private String _keystoreType="JKS"; // type of the key store
73
74 /** Set to true if we require client certificate authentication. */
75 private boolean _needClientAuth=false;
76 private boolean _wantClientAuth=false;
77 private boolean _allowRenegotiate=false;
78
79 private transient Password _password;
80 private transient Password _keyPassword;
81 private transient Password _trustPassword;
82 private String _protocol="TLS";
83 private String _provider;
84 private String _secureRandomAlgorithm; // cert algorithm
85 private String _sslKeyManagerFactoryAlgorithm=DEFAULT_KEYSTORE_ALGORITHM;
86 private String _sslTrustManagerFactoryAlgorithm=DEFAULT_TRUSTSTORE_ALGORITHM;
87 private String _truststorePath;
88 private String _truststoreType="JKS"; // type of the key store
89 private SSLContext _context;
90 Buffers _sslBuffers;
91
92
93 /**
94 * Return the chain of X509 certificates used to negotiate the SSL Session.
95 * <p>
96 * Note: in order to do this we must convert a
97 * javax.security.cert.X509Certificate[], as used by JSSE to a
98 * java.security.cert.X509Certificate[],as required by the Servlet specs.
99 *
100 * @param sslSession
101 * the javax.net.ssl.SSLSession to use as the source of the
102 * cert chain.
103 * @return the chain of java.security.cert.X509Certificates used to
104 * negotiate the SSL connection. <br>
105 * Will be null if the chain is missing or empty.
106 */
107
108
109 /* ------------------------------------------------------------ */
110 /**
111 * Allow the Listener a chance to customise the request. before the server
112 * does its stuff. <br>
113 * This allows the required attributes to be set for SSL requests. <br>
114 * The requirements of the Servlet specs are:
115 * <ul>
116 * <li> an attribute named "javax.servlet.request.ssl_session_id" of type
117 * String (since Servlet Spec 3.0).</li>
118 * <li> an attribute named "javax.servlet.request.cipher_suite" of type
119 * String.</li>
120 * <li> an attribute named "javax.servlet.request.key_size" of type Integer.</li>
121 * <li> an attribute named "javax.servlet.request.X509Certificate" of type
122 * java.security.cert.X509Certificate[]. This is an array of objects of type
123 * X509Certificate, the order of this array is defined as being in ascending
124 * order of trust. The first certificate in the chain is the one set by the
125 * client, the next is the one used to authenticate the first, and so on.
126 * </li>
127 * </ul>
128 *
129 * @param endpoint
130 * The Socket the request arrived on. This should be a
131 * {@link SocketEndPoint} wrapping a {@link SSLSocket}.
132 * @param request
133 * HttpRequest to be customised.
134 */
135 @Override
136 public void customize(EndPoint endpoint, Request request) throws IOException
137 {
138 super.customize(endpoint,request);
139 request.setScheme(HttpSchemes.HTTPS);
140
141 SslSelectChannelEndPoint sslHttpChannelEndpoint=(SslSelectChannelEndPoint)endpoint;
142 SSLEngine sslEngine=sslHttpChannelEndpoint.getSSLEngine();
143 SSLSession sslSession=sslEngine.getSession();
144
145 SslCertificates.customize(sslSession,endpoint,request);
146 }
147
148 /* ------------------------------------------------------------ */
149 public SslSelectChannelConnector()
150 {
151 }
152
153 /* ------------------------------------------------------------ */
154 /**
155 * @return True if SSL re-negotiation is allowed (default false)
156 */
157 public boolean isAllowRenegotiate()
158 {
159 return _allowRenegotiate;
160 }
161
162 /* ------------------------------------------------------------ */
163 /**
164 * Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered
165 * a vulnerability in SSL/TLS with re-negotiation. If your JVM
166 * does not have CVE-2009-3555 fixed, then re-negotiation should
167 * not be allowed.
168 * @param allowRenegotiate true if re-negotiation is allowed (default false)
169 */
170 public void setAllowRenegotiate(boolean allowRenegotiate)
171 {
172 _allowRenegotiate = allowRenegotiate;
173 }
174
175 /* ------------------------------------------------------------ */
176 /**
177 * @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
178 */
179 public String[] getExcludeCipherSuites()
180 {
181 return _excludeCipherSuites;
182 }
183
184 /* ------------------------------------------------------------ */
185 /**
186 * @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[])
187 */
188 public void setExcludeCipherSuites(String[] cipherSuites)
189 {
190 this._excludeCipherSuites=cipherSuites;
191 }
192
193 /* ------------------------------------------------------------ */
194 /**
195 * @see org.eclipse.jetty.server.ssl.SslConnector#getExcludeCipherSuites()
196 */
197 public String[] getIncludeCipherSuites()
198 {
199 return _includeCipherSuites;
200 }
201
202 /* ------------------------------------------------------------ */
203 /**
204 * @see org.eclipse.jetty.server.ssl.SslConnector#setExcludeCipherSuites(java.lang.String[])
205 */
206 public void setIncludeCipherSuites(String[] cipherSuites)
207 {
208 this._includeCipherSuites=cipherSuites;
209 }
210
211 /* ------------------------------------------------------------ */
212 /**
213 * @see org.eclipse.jetty.server.ssl.SslConnector#setPassword(java.lang.String)
214 */
215 public void setPassword(String password)
216 {
217 _password=Password.getPassword(PASSWORD_PROPERTY,password,null);
218 }
219
220 /* ------------------------------------------------------------ */
221 /**
222 * @see org.eclipse.jetty.server.ssl.SslConnector#setTrustPassword(java.lang.String)
223 */
224 public void setTrustPassword(String password)
225 {
226 _trustPassword=Password.getPassword(PASSWORD_PROPERTY,password,null);
227 }
228
229 /* ------------------------------------------------------------ */
230 /**
231 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeyPassword(java.lang.String)
232 */
233 public void setKeyPassword(String password)
234 {
235 _keyPassword=Password.getPassword(KEYPASSWORD_PROPERTY,password,null);
236 }
237
238 /* ------------------------------------------------------------ */
239 /**
240 * @deprecated use {@link #getSslKeyManagerFactoryAlgorithm()} or
241 * {@link #getSslTrustManagerFactoryAlgorithm()}
242 */
243 @Deprecated
244 public String getAlgorithm()
245 {
246 return getSslKeyManagerFactoryAlgorithm();
247 }
248
249 /* ------------------------------------------------------------ */
250 /**
251 * @deprecated use {@link #setSslKeyManagerFactoryAlgorithm(String)} or
252 * {@link #setSslTrustManagerFactoryAlgorithm(String)}
253 */
254 @Deprecated
255 public void setAlgorithm(String algorithm)
256 {
257 setSslKeyManagerFactoryAlgorithm(algorithm);
258 setSslTrustManagerFactoryAlgorithm(algorithm);
259 }
260
261 /* ------------------------------------------------------------ */
262 /**
263 * @see org.eclipse.jetty.server.ssl.SslConnector#getProtocol()
264 */
265 public String getProtocol()
266 {
267 return _protocol;
268 }
269
270 /* ------------------------------------------------------------ */
271 /**
272 * @see org.eclipse.jetty.server.ssl.SslConnector#setProtocol(java.lang.String)
273 */
274 public void setProtocol(String protocol)
275 {
276 _protocol=protocol;
277 }
278
279 /* ------------------------------------------------------------ */
280 /**
281 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeystore(java.lang.String)
282 */
283 public void setKeystore(String keystore)
284 {
285 _keystorePath=keystore;
286 }
287
288 /* ------------------------------------------------------------ */
289 /**
290 * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystore()
291 */
292 public String getKeystore()
293 {
294 return _keystorePath;
295 }
296
297 /* ------------------------------------------------------------ */
298 /**
299 * @see org.eclipse.jetty.server.ssl.SslConnector#getKeystoreType()
300 */
301 public String getKeystoreType()
302 {
303 return (_keystoreType);
304 }
305
306 /* ------------------------------------------------------------ */
307 /**
308 * @see org.eclipse.jetty.server.ssl.SslConnector#getNeedClientAuth()
309 */
310 public boolean getNeedClientAuth()
311 {
312 return _needClientAuth;
313 }
314
315 /* ------------------------------------------------------------ */
316 /**
317 * @see org.eclipse.jetty.server.ssl.SslConnector#getWantClientAuth()
318 */
319 public boolean getWantClientAuth()
320 {
321 return _wantClientAuth;
322 }
323
324 /* ------------------------------------------------------------ */
325 /**
326 * @see org.eclipse.jetty.server.ssl.SslConnector#setNeedClientAuth(boolean)
327 */
328 public void setNeedClientAuth(boolean needClientAuth)
329 {
330 _needClientAuth=needClientAuth;
331 }
332
333 /* ------------------------------------------------------------ */
334 /**
335 * @see org.eclipse.jetty.server.ssl.SslConnector#setWantClientAuth(boolean)
336 */
337 public void setWantClientAuth(boolean wantClientAuth)
338 {
339 _wantClientAuth=wantClientAuth;
340 }
341
342 /* ------------------------------------------------------------ */
343 /**
344 * @see org.eclipse.jetty.server.ssl.SslConnector#setKeystoreType(java.lang.String)
345 */
346 public void setKeystoreType(String keystoreType)
347 {
348 _keystoreType=keystoreType;
349 }
350
351 /* ------------------------------------------------------------ */
352 /**
353 * @see org.eclipse.jetty.server.ssl.SslConnector#getProvider()
354 */
355 public String getProvider()
356 {
357 return _provider;
358 }
359
360 /* ------------------------------------------------------------ */
361 /**
362 * @see org.eclipse.jetty.server.ssl.SslConnector#getSecureRandomAlgorithm()
363 */
364 public String getSecureRandomAlgorithm()
365 {
366 return (this._secureRandomAlgorithm);
367 }
368
369 /* ------------------------------------------------------------ */
370 /**
371 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslKeyManagerFactoryAlgorithm()
372 */
373 public String getSslKeyManagerFactoryAlgorithm()
374 {
375 return (this._sslKeyManagerFactoryAlgorithm);
376 }
377
378 /* ------------------------------------------------------------ */
379 /**
380 * @see org.eclipse.jetty.server.ssl.SslConnector#getSslTrustManagerFactoryAlgorithm()
381 */
382 public String getSslTrustManagerFactoryAlgorithm()
383 {
384 return (this._sslTrustManagerFactoryAlgorithm);
385 }
386
387 /* ------------------------------------------------------------ */
388 /**
389 * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststore()
390 */
391 public String getTruststore()
392 {
393 return _truststorePath;
394 }
395
396 /* ------------------------------------------------------------ */
397 /**
398 * @see org.eclipse.jetty.server.ssl.SslConnector#getTruststoreType()
399 */
400 public String getTruststoreType()
401 {
402 return _truststoreType;
403 }
404
405 /* ------------------------------------------------------------ */
406 /**
407 * @see org.eclipse.jetty.server.ssl.SslConnector#setProvider(java.lang.String)
408 */
409 public void setProvider(String provider)
410 {
411 _provider=provider;
412 }
413
414 /* ------------------------------------------------------------ */
415 /**
416 * @see org.eclipse.jetty.server.ssl.SslConnector#setSecureRandomAlgorithm(java.lang.String)
417 */
418 public void setSecureRandomAlgorithm(String algorithm)
419 {
420 this._secureRandomAlgorithm=algorithm;
421 }
422
423 /* ------------------------------------------------------------ */
424 /**
425 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslKeyManagerFactoryAlgorithm(java.lang.String)
426 */
427 public void setSslKeyManagerFactoryAlgorithm(String algorithm)
428 {
429 this._sslKeyManagerFactoryAlgorithm=algorithm;
430 }
431
432 /* ------------------------------------------------------------ */
433 /**
434 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslTrustManagerFactoryAlgorithm(java.lang.String)
435 */
436 public void setSslTrustManagerFactoryAlgorithm(String algorithm)
437 {
438 this._sslTrustManagerFactoryAlgorithm=algorithm;
439 }
440
441 /* ------------------------------------------------------------ */
442 /**
443 * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststore(java.lang.String)
444 */
445 public void setTruststore(String truststore)
446 {
447 _truststorePath=truststore;
448 }
449
450 /* ------------------------------------------------------------ */
451 /**
452 * @see org.eclipse.jetty.server.ssl.SslConnector#setTruststoreType(java.lang.String)
453 */
454 public void setTruststoreType(String truststoreType)
455 {
456 _truststoreType=truststoreType;
457 }
458
459 /* ------------------------------------------------------------ */
460 /**
461 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
462 */
463 public void setSslContext(SSLContext sslContext)
464 {
465 _context = sslContext;
466 }
467
468 /* ------------------------------------------------------------ */
469 /**
470 * @see org.eclipse.jetty.server.ssl.SslConnector#setSslContext(javax.net.ssl.SSLContext)
471 */
472 public SSLContext getSslContext()
473 {
474 try
475 {
476 if (_context == null)
477 _context=createSSLContext();
478 }
479 catch(Exception e)
480 {
481 throw new RuntimeException(e);
482 }
483
484 return _context;
485 }
486
487 /* ------------------------------------------------------------ */
488 /**
489 * By default, we're confidential, given we speak SSL. But, if we've been
490 * told about an confidential port, and said port is not our port, then
491 * we're not. This allows separation of listeners providing INTEGRAL versus
492 * CONFIDENTIAL constraints, such as one SSL listener configured to require
493 * client certs providing CONFIDENTIAL, whereas another SSL listener not
494 * requiring client certs providing mere INTEGRAL constraints.
495 */
496 @Override
497 public boolean isConfidential(Request request)
498 {
499 final int confidentialPort=getConfidentialPort();
500 return confidentialPort==0||confidentialPort==request.getServerPort();
501 }
502
503 /* ------------------------------------------------------------ */
504 /**
505 * By default, we're integral, given we speak SSL. But, if we've been told
506 * about an integral port, and said port is not our port, then we're not.
507 * This allows separation of listeners providing INTEGRAL versus
508 * CONFIDENTIAL constraints, such as one SSL listener configured to require
509 * client certs providing CONFIDENTIAL, whereas another SSL listener not
510 * requiring client certs providing mere INTEGRAL constraints.
511 */
512 @Override
513 public boolean isIntegral(Request request)
514 {
515 final int integralPort=getIntegralPort();
516 return integralPort==0||integralPort==request.getServerPort();
517 }
518
519 /* ------------------------------------------------------------------------------- */
520 @Override
521 protected SelectChannelEndPoint newEndPoint(SocketChannel channel, SelectSet selectSet, SelectionKey key) throws IOException
522 {
523 SslSelectChannelEndPoint endp = new SslSelectChannelEndPoint(_sslBuffers,channel,selectSet,key,createSSLEngine());
524 endp.setAllowRenegotiate(_allowRenegotiate);
525 return endp;
526 }
527
528 /* ------------------------------------------------------------------------------- */
529 @Override
530 protected Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint)
531 {
532 HttpConnection connection=(HttpConnection)super.newConnection(channel,endpoint);
533 ((HttpParser)connection.getParser()).setForceContentBuffer(true);
534 return connection;
535 }
536
537 /* ------------------------------------------------------------ */
538 protected SSLEngine createSSLEngine() throws IOException
539 {
540 SSLEngine engine = null;
541 try
542 {
543 engine = _context.createSSLEngine();
544 engine.setUseClientMode(false);
545
546 if (_wantClientAuth)
547 engine.setWantClientAuth(_wantClientAuth);
548 if (_needClientAuth)
549 engine.setNeedClientAuth(_needClientAuth);
550
551 if ((_excludeCipherSuites != null && _excludeCipherSuites.length > 0) || (_includeCipherSuites != null && _includeCipherSuites.length > 0))
552 {
553 List<String> includedCSList;
554 if (_includeCipherSuites != null)
555 {
556 includedCSList = Arrays.asList(_includeCipherSuites);
557 }
558 else
559 {
560 includedCSList = new ArrayList<String>();
561 }
562 List<String> excludedCSList;
563 if (_excludeCipherSuites != null)
564 {
565 excludedCSList = Arrays.asList(_excludeCipherSuites);
566 }
567 else
568 {
569 excludedCSList = new ArrayList<String>();
570 }
571 String[] enabledCipherSuites = engine.getEnabledCipherSuites();
572 List<String> enabledCSList = new ArrayList<String>(Arrays.asList(enabledCipherSuites));
573
574 String[] supportedCipherSuites = engine.getSupportedCipherSuites();
575 List<String> supportedCSList = Arrays.asList(supportedCipherSuites);
576
577 for (String cipherName : includedCSList)
578 {
579 if ((!enabledCSList.contains(cipherName)) && supportedCSList.contains(cipherName))
580 {
581 enabledCSList.add(cipherName);
582 }
583 }
584
585 for (String cipherName : excludedCSList)
586 {
587 if (enabledCSList.contains(cipherName))
588 {
589 enabledCSList.remove(cipherName);
590 }
591 }
592 enabledCipherSuites = enabledCSList.toArray(new String[0]);
593
594 engine.setEnabledCipherSuites(enabledCipherSuites);
595 }
596 }
597 catch (Exception e)
598 {
599 Log.warn("Error creating sslEngine -- closing this connector",e);
600 close();
601 throw new IllegalStateException(e);
602 }
603 return engine;
604 }
605
606 @Override
607 protected void doStart() throws Exception
608 {
609 if (_context == null)
610 _context=createSSLContext();
611
612 SSLEngine engine=createSSLEngine();
613 SSLSession ssl_session=engine.getSession();
614
615 ThreadLocalBuffers buffers = new ThreadLocalBuffers()
616 {
617 @Override
618 protected Buffer newBuffer(int size)
619 {
620 // TODO indirect?
621 return new DirectNIOBuffer(size);
622 }
623 @Override
624 protected Buffer newHeader(int size)
625 {
626 // TODO indirect?
627 return new DirectNIOBuffer(size);
628 }
629 @Override
630 protected boolean isHeader(Buffer buffer)
631 {
632 return true;
633 }
634 };
635 buffers.setBufferSize(ssl_session.getApplicationBufferSize());
636 buffers.setHeaderSize(ssl_session.getApplicationBufferSize());
637 _sslBuffers=buffers;
638
639 if (getRequestHeaderSize()<ssl_session.getApplicationBufferSize())
640 setRequestHeaderSize(ssl_session.getApplicationBufferSize());
641 if (getRequestBufferSize()<ssl_session.getApplicationBufferSize())
642 setRequestBufferSize(ssl_session.getApplicationBufferSize());
643
644 super.doStart();
645 }
646
647 /* ------------------------------------------------------------ */
648 protected SSLContext createSSLContext() throws Exception
649 {
650 KeyManager[] keyManagers=getKeyManagers();
651
652 TrustManager[] trustManagers=getTrustManagers();
653
654 SecureRandom secureRandom=_secureRandomAlgorithm==null?null:SecureRandom.getInstance(_secureRandomAlgorithm);
655 SSLContext context=_provider==null?SSLContext.getInstance(_protocol):SSLContext.getInstance(_protocol,_provider);
656 context.init(keyManagers,trustManagers,secureRandom);
657 return context;
658 }
659
660 /* ------------------------------------------------------------ */
661 protected KeyManager[] getKeyManagers() throws Exception
662 {
663 KeyStore keyStore = getKeyStore(_keystorePath, _keystoreType, _password==null?null:_password.toString());
664
665 KeyManagerFactory keyManagerFactory=KeyManagerFactory.getInstance(_sslKeyManagerFactoryAlgorithm);
666 keyManagerFactory.init(keyStore,_keyPassword==null?(_password==null?null:_password.toString().toCharArray()):_keyPassword.toString().toCharArray());
667 return keyManagerFactory.getKeyManagers();
668 }
669
670 /* ------------------------------------------------------------ */
671 protected TrustManager[] getTrustManagers() throws Exception
672 {
673 if (_truststorePath==null)
674 {
675 _truststorePath=_keystorePath;
676 _truststoreType=_keystoreType;
677 _trustPassword = _password;
678 _sslTrustManagerFactoryAlgorithm = _sslKeyManagerFactoryAlgorithm;
679 }
680
681 KeyStore trustStore = getKeyStore(_truststorePath, _truststoreType, _trustPassword==null?null:_trustPassword.toString());
682
683 TrustManagerFactory trustManagerFactory=TrustManagerFactory.getInstance(_sslTrustManagerFactoryAlgorithm);
684 trustManagerFactory.init(trustStore);
685 return trustManagerFactory.getTrustManagers();
686 }
687
688 /* ------------------------------------------------------------ */
689 protected KeyStore getKeyStore(String keystorePath, String keystoreType, String keystorePassword) throws Exception
690 {
691 KeyStore keystore;
692 InputStream keystoreInputStream = null;
693 try
694 {
695 if (keystorePath!=null)
696 keystoreInputStream = Resource.newResource(keystorePath).getInputStream();
697 keystore=KeyStore.getInstance(keystoreType);
698 keystore.load(keystoreInputStream,keystorePassword==null?null:keystorePassword.toString().toCharArray());
699 return keystore;
700 }
701 finally
702 {
703 if (keystoreInputStream != null)
704 keystoreInputStream.close();
705 }
706 }
707
708 }