View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2015 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.util.ssl;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.IOException;
23  import java.net.InetAddress;
24  import java.net.InetSocketAddress;
25  import java.net.MalformedURLException;
26  import java.security.KeyStore;
27  import java.security.SecureRandom;
28  import java.security.Security;
29  import java.security.cert.CRL;
30  import java.security.cert.CertStore;
31  import java.security.cert.Certificate;
32  import java.security.cert.CollectionCertStoreParameters;
33  import java.security.cert.PKIXBuilderParameters;
34  import java.security.cert.X509CertSelector;
35  import java.security.cert.X509Certificate;
36  import java.util.ArrayList;
37  import java.util.Arrays;
38  import java.util.Collection;
39  import java.util.Collections;
40  import java.util.Comparator;
41  import java.util.HashMap;
42  import java.util.Iterator;
43  import java.util.LinkedHashSet;
44  import java.util.List;
45  import java.util.Map;
46  import java.util.Set;
47  import java.util.regex.Matcher;
48  import java.util.regex.Pattern;
49  
50  import javax.net.ssl.CertPathTrustManagerParameters;
51  import javax.net.ssl.KeyManager;
52  import javax.net.ssl.KeyManagerFactory;
53  import javax.net.ssl.SNIHostName;
54  import javax.net.ssl.SNIMatcher;
55  import javax.net.ssl.SNIServerName;
56  import javax.net.ssl.SSLContext;
57  import javax.net.ssl.SSLEngine;
58  import javax.net.ssl.SSLParameters;
59  import javax.net.ssl.SSLPeerUnverifiedException;
60  import javax.net.ssl.SSLServerSocket;
61  import javax.net.ssl.SSLServerSocketFactory;
62  import javax.net.ssl.SSLSession;
63  import javax.net.ssl.SSLSocket;
64  import javax.net.ssl.SSLSocketFactory;
65  import javax.net.ssl.StandardConstants;
66  import javax.net.ssl.TrustManager;
67  import javax.net.ssl.TrustManagerFactory;
68  import javax.net.ssl.X509ExtendedKeyManager;
69  import javax.net.ssl.X509TrustManager;
70  
71  import org.eclipse.jetty.util.StringUtil;
72  import org.eclipse.jetty.util.component.AbstractLifeCycle;
73  import org.eclipse.jetty.util.log.Log;
74  import org.eclipse.jetty.util.log.Logger;
75  import org.eclipse.jetty.util.resource.Resource;
76  import org.eclipse.jetty.util.security.CertificateUtils;
77  import org.eclipse.jetty.util.security.CertificateValidator;
78  import org.eclipse.jetty.util.security.Password;
79  
80  
81  /**
82   * SslContextFactory is used to configure SSL connectors
83   * as well as HttpClient. It holds all SSL parameters and
84   * creates SSL context based on these parameters to be
85   * used by the SSL connectors.
86   */
87  
88  /**
89   */
90  public class SslContextFactory extends AbstractLifeCycle
91  {
92      public final static TrustManager[] TRUST_ALL_CERTS = new X509TrustManager[]{new X509TrustManager()
93      {
94          public java.security.cert.X509Certificate[] getAcceptedIssuers()
95          {
96              return new java.security.cert.X509Certificate[]{};
97          }
98  
99          public void checkClientTrusted(java.security.cert.X509Certificate[] certs, String authType)
100         {
101         }
102 
103         public void checkServerTrusted(java.security.cert.X509Certificate[] certs, String authType)
104         {
105         }
106     }};
107 
108     static final Logger LOG = Log.getLogger(SslContextFactory.class);
109 
110     public static final String DEFAULT_KEYMANAGERFACTORY_ALGORITHM =
111         (Security.getProperty("ssl.KeyManagerFactory.algorithm") == null ?
112                 KeyManagerFactory.getDefaultAlgorithm() : Security.getProperty("ssl.KeyManagerFactory.algorithm"));
113 
114     public static final String DEFAULT_TRUSTMANAGERFACTORY_ALGORITHM =
115         (Security.getProperty("ssl.TrustManagerFactory.algorithm") == null ?
116                 TrustManagerFactory.getDefaultAlgorithm() : Security.getProperty("ssl.TrustManagerFactory.algorithm"));
117 
118     /** String name of key password property. */
119     public static final String KEYPASSWORD_PROPERTY = "org.eclipse.jetty.ssl.keypassword";
120 
121     /** String name of keystore password property. */
122     public static final String PASSWORD_PROPERTY = "org.eclipse.jetty.ssl.password";
123 
124     /** Excluded protocols. */
125     private final Set<String> _excludeProtocols = new LinkedHashSet<>();
126 
127     /** Included protocols. */
128     private final Set<String> _includeProtocols = new LinkedHashSet<>();
129 
130     /** Selected protocols. */
131     private String[] _selectedProtocols;
132 
133     /** Excluded cipher suites. */
134     private final Set<String> _excludeCipherSuites = new LinkedHashSet<>();
135 
136     /** Included cipher suites. */
137     private final List<String> _includeCipherSuites = new ArrayList<>();
138     private boolean _useCipherSuitesOrder=true;
139 
140     /** Cipher comparator for ordering ciphers */
141     Comparator<String> _cipherComparator;
142 
143     /** Selected cipher suites. Combination of includes, excludes, available and ordering */
144     private String[] _selectedCipherSuites;
145 
146     /** Keystore path. */
147     private Resource _keyStoreResource;
148     /** Keystore provider name */
149     private String _keyStoreProvider;
150     /** Keystore type */
151     private String _keyStoreType = "JKS";
152 
153     /** SSL certificate alias */
154     private String _certAlias;
155     private final Map<String,X509> _aliasX509 = new HashMap<>();
156     private final Map<String,X509> _certHosts = new HashMap<>();
157     private final Map<String,X509> _certWilds = new HashMap<>();
158 
159     /** Truststore path */
160     private Resource _trustStoreResource;
161     /** Truststore provider name */
162     private String _trustStoreProvider;
163     /** Truststore type */
164     private String _trustStoreType = "JKS";
165 
166     /** Set to true if client certificate authentication is required */
167     private boolean _needClientAuth = false;
168     /** Set to true if client certificate authentication is desired */
169     private boolean _wantClientAuth = false;
170 
171     /** Keystore password */
172     private Password _keyStorePassword;
173     /** Key manager password */
174     private Password _keyManagerPassword;
175     /** Truststore password */
176     private Password _trustStorePassword;
177 
178     /** SSL provider name */
179     private String _sslProvider;
180     /** SSL protocol name */
181     private String _sslProtocol = "TLS";
182 
183     /** SecureRandom algorithm */
184     private String _secureRandomAlgorithm;
185     /** KeyManager factory algorithm */
186     private String _keyManagerFactoryAlgorithm = DEFAULT_KEYMANAGERFACTORY_ALGORITHM;
187     /** TrustManager factory algorithm */
188     private String _trustManagerFactoryAlgorithm = DEFAULT_TRUSTMANAGERFACTORY_ALGORITHM;
189 
190     /** Set to true if SSL certificate validation is required */
191     private boolean _validateCerts;
192     /** Set to true if SSL certificate of the peer validation is required */
193     private boolean _validatePeerCerts;
194     /** Maximum certification path length (n - number of intermediate certs, -1 for unlimited) */
195     private int _maxCertPathLength = -1;
196     /** Path to file that contains Certificate Revocation List */
197     private String _crlPath;
198     /** Set to true to enable CRL Distribution Points (CRLDP) support */
199     private boolean _enableCRLDP = false;
200     /** Set to true to enable On-Line Certificate Status Protocol (OCSP) support */
201     private boolean _enableOCSP = false;
202     /** Location of OCSP Responder */
203     private String _ocspResponderURL;
204 
205     /** SSL keystore */
206     private KeyStore _setKeyStore;
207     /** SSL truststore */
208     private KeyStore _setTrustStore;
209     /** Set to true to enable SSL Session caching */
210     private boolean _sessionCachingEnabled = true;
211     /** SSL session cache size */
212     private int _sslSessionCacheSize;
213     /** SSL session timeout */
214     private int _sslSessionTimeout;
215 
216     /** SSL context */
217     private SSLContext _setContext;
218 
219     /** EndpointIdentificationAlgorithm - when set to "HTTPS" hostname verification will be enabled */
220     private String _endpointIdentificationAlgorithm = null;
221 
222     /** Whether to blindly trust certificates */
223     private boolean _trustAll;
224 
225     /** Whether TLS renegotiation is allowed */
226     private boolean _renegotiationAllowed = true;
227 
228     protected Factory _factory;
229 
230 
231 
232 
233     /**
234      * Construct an instance of SslContextFactory
235      * Default constructor for use in XmlConfiguration files
236      */
237     public SslContextFactory()
238     {
239         this(false);
240     }
241 
242     /**
243      * Construct an instance of SslContextFactory
244      * Default constructor for use in XmlConfiguration files
245      * @param trustAll whether to blindly trust all certificates
246      * @see #setTrustAll(boolean)
247      */
248     public SslContextFactory(boolean trustAll)
249     {
250         setTrustAll(trustAll);
251         addExcludeProtocols("SSL", "SSLv2", "SSLv2Hello", "SSLv3");
252         setExcludeCipherSuites(
253                 "SSL_RSA_WITH_DES_CBC_SHA",
254                 "SSL_DHE_RSA_WITH_DES_CBC_SHA",
255                 "SSL_DHE_DSS_WITH_DES_CBC_SHA",
256                 "SSL_RSA_EXPORT_WITH_RC4_40_MD5",
257                 "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA",
258                 "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
259                 "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA");
260 }
261 
262     /**
263      * Construct an instance of SslContextFactory
264      * @param keyStorePath default keystore location
265      */
266     public SslContextFactory(String keyStorePath)
267     {
268         setKeyStorePath(keyStorePath);
269     }
270 
271     public String[] getSelectedProtocols()
272     {
273         return Arrays.copyOf(_selectedProtocols,_selectedProtocols.length);
274     }
275 
276     public String[] getSelectedCipherSuites()
277     {
278         return Arrays.copyOf(_selectedCipherSuites,_selectedCipherSuites.length);
279     }
280 
281     public Comparator<String> getCipherComparator()
282     {
283         return _cipherComparator;
284     }
285 
286     public void setCipherComparator(Comparator<String> cipherComparator)
287     {
288         if (cipherComparator!=null)
289             setUseCipherSuitesOrder(true);
290         _cipherComparator = cipherComparator;
291     }
292 
293     public Set<String> getAliases()
294     {
295         return Collections.unmodifiableSet(_aliasX509.keySet());
296     }
297 
298     public X509 getX509(String alias)
299     {
300         return _aliasX509.get(alias);
301     }
302 
303     /**
304      * Create the SSLContext object and start the lifecycle
305      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
306      */
307     @Override
308     protected void doStart() throws Exception
309     {
310         SSLContext context = _setContext;
311         KeyStore keyStore = _setKeyStore;
312         KeyStore trustStore = _setTrustStore;
313 
314         if (context == null)
315         {
316             // Is this an empty factory?
317             if (keyStore==null && _keyStoreResource == null && trustStore==null && _trustStoreResource == null )
318             {
319                 TrustManager[] trust_managers=null;
320 
321                 if (_trustAll)
322                 {
323                     if (LOG.isDebugEnabled())
324                         LOG.debug("No keystore or trust store configured.  ACCEPTING UNTRUSTED CERTIFICATES!!!!!");
325                     // Create a trust manager that does not validate certificate chains
326                     trust_managers = TRUST_ALL_CERTS;
327                 }
328 
329                 SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
330                 context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol, _sslProvider);
331                 context.init(null, trust_managers, secureRandom);
332             }
333             else
334             {
335                 if (keyStore==null)
336                     keyStore=loadKeyStore(_keyStoreResource);
337                 if (trustStore==null)
338                     trustStore=loadTrustStore(_trustStoreResource);
339 
340                 Collection<? extends CRL> crls = loadCRL(_crlPath);
341 
342                 // Look for X.509 certificates to create alias map
343                 _certHosts.clear();
344                 if (keyStore!=null)
345                 {
346                     for (String alias : Collections.list(keyStore.aliases()))
347                     {
348                         Certificate certificate = keyStore.getCertificate(alias);
349                         if (certificate!=null && "X.509".equals(certificate.getType()))
350                         {
351                             X509Certificate x509C = (X509Certificate)certificate;
352 
353                             // Exclude certificates with special uses
354                             if (X509.isCertSign(x509C))
355                             {
356                                 if (LOG.isDebugEnabled())
357                                     LOG.debug("Skipping "+x509C);
358                                 continue;
359                             }
360                             X509 x509 = new X509(alias,x509C);
361                             _aliasX509.put(alias,x509);
362 
363                             if (_validateCerts)
364                             {
365                                 CertificateValidator validator = new CertificateValidator(trustStore, crls);
366                                 validator.setMaxCertPathLength(_maxCertPathLength);
367                                 validator.setEnableCRLDP(_enableCRLDP);
368                                 validator.setEnableOCSP(_enableOCSP);
369                                 validator.setOcspResponderURL(_ocspResponderURL);
370                                 validator.validate(keyStore, x509C); // TODO what about truststore?
371                             }
372 
373                             LOG.info("x509={} for {}",x509,this);
374 
375                             for (String h:x509.getHosts())
376                                 _certHosts.put(h,x509);
377                             for (String w:x509.getWilds())
378                                 _certWilds.put(w,x509);
379                         }
380                     }
381                 }
382 
383                 // Instantiate key and trust managers
384                 KeyManager[] keyManagers = getKeyManagers(keyStore);
385                 TrustManager[] trustManagers = getTrustManagers(trustStore,crls);
386 
387                 // Initialize context
388                 SecureRandom secureRandom = (_secureRandomAlgorithm == null)?null:SecureRandom.getInstance(_secureRandomAlgorithm);
389                 context = _sslProvider == null ? SSLContext.getInstance(_sslProtocol) : SSLContext.getInstance(_sslProtocol, _sslProvider);
390                 context.init(keyManagers,trustManagers,secureRandom);
391             }
392         }
393 
394         // select the protocols and ciphers
395         SSLEngine sslEngine=context.createSSLEngine();
396         selectCipherSuites(
397                 sslEngine.getEnabledCipherSuites(),
398                 sslEngine.getSupportedCipherSuites());
399         selectProtocols(sslEngine.getEnabledProtocols(),sslEngine.getSupportedProtocols());
400 
401         _factory = new Factory(keyStore,trustStore,context);
402         if (LOG.isDebugEnabled())
403         {
404             LOG.debug("Selected Protocols {} of {}",Arrays.asList(_selectedProtocols),Arrays.asList(sslEngine.getSupportedProtocols()));
405             LOG.debug("Selected Ciphers   {} of {}",Arrays.asList(_selectedCipherSuites),Arrays.asList(sslEngine.getSupportedCipherSuites()));
406         }
407     }
408 
409     @Override
410     protected void doStop() throws Exception
411     {
412         _factory = null;
413         super.doStop();
414         _certHosts.clear();
415         _certWilds.clear();
416         _aliasX509.clear();
417     }
418 
419     /**
420      * @return The array of protocol names to exclude from
421      * {@link SSLEngine#setEnabledProtocols(String[])}
422      */
423     public String[] getExcludeProtocols()
424     {
425         return _excludeProtocols.toArray(new String[_excludeProtocols.size()]);
426     }
427 
428     /**
429      * @param protocols
430      *            The array of protocol names to exclude from
431      *            {@link SSLEngine#setEnabledProtocols(String[])}
432      */
433     public void setExcludeProtocols(String... protocols)
434     {
435         checkNotStarted();
436         _excludeProtocols.clear();
437         _excludeProtocols.addAll(Arrays.asList(protocols));
438     }
439 
440     /**
441      * @param protocol Protocol names to add to {@link SSLEngine#setEnabledProtocols(String[])}
442      */
443     public void addExcludeProtocols(String... protocol)
444     {
445         checkNotStarted();
446         _excludeProtocols.addAll(Arrays.asList(protocol));
447     }
448 
449     /**
450      * @return The array of protocol names to include in
451      * {@link SSLEngine#setEnabledProtocols(String[])}
452      */
453     public String[] getIncludeProtocols()
454     {
455         return _includeProtocols.toArray(new String[_includeProtocols.size()]);
456     }
457 
458     /**
459      * @param protocols
460      *            The array of protocol names to include in
461      *            {@link SSLEngine#setEnabledProtocols(String[])}
462      */
463     public void setIncludeProtocols(String... protocols)
464     {
465         checkNotStarted();
466         _includeProtocols.clear();
467         _includeProtocols.addAll(Arrays.asList(protocols));
468     }
469 
470     /**
471      * @return The array of cipher suite names to exclude from
472      * {@link SSLEngine#setEnabledCipherSuites(String[])}
473      */
474     public String[] getExcludeCipherSuites()
475     {
476         return _excludeCipherSuites.toArray(new String[_excludeCipherSuites.size()]);
477     }
478 
479     /**
480      * You can either use the exact cipher suite name or a a regular expression.
481      * @param cipherSuites
482      *            The array of cipher suite names to exclude from
483      *            {@link SSLEngine#setEnabledCipherSuites(String[])}
484      */
485     public void setExcludeCipherSuites(String... cipherSuites)
486     {
487         checkNotStarted();
488         _excludeCipherSuites.clear();
489         _excludeCipherSuites.addAll(Arrays.asList(cipherSuites));
490     }
491 
492     /**
493      * @param cipher Cipher names to add to {@link SSLEngine#setEnabledCipherSuites(String[])}
494      */
495     public void addExcludeCipherSuites(String... cipher)
496     {
497         checkNotStarted();
498         _excludeCipherSuites.addAll(Arrays.asList(cipher));
499     }
500 
501     /**
502      * @return The array of cipher suite names to include in
503      * {@link SSLEngine#setEnabledCipherSuites(String[])}
504      */
505     public String[] getIncludeCipherSuites()
506     {
507         return _includeCipherSuites.toArray(new String[_includeCipherSuites.size()]);
508     }
509 
510     /**
511      * You can either use the exact cipher suite name or a a regular expression.
512      * @param cipherSuites
513      *            The array of cipher suite names to include in
514      *            {@link SSLEngine#setEnabledCipherSuites(String[])}
515      */
516     public void setIncludeCipherSuites(String... cipherSuites)
517     {
518         checkNotStarted();
519         _includeCipherSuites.clear();
520         _includeCipherSuites.addAll(Arrays.asList(cipherSuites));
521     }
522 
523     public boolean isUseCipherSuitesOrder()
524     {
525         return _useCipherSuitesOrder;
526     }
527 
528     public void setUseCipherSuitesOrder(boolean useCipherSuitesOrder)
529     {
530         _useCipherSuitesOrder = useCipherSuitesOrder;
531     }
532 
533     /**
534      * @return The file or URL of the SSL Key store.
535      */
536     public String getKeyStorePath()
537     {
538         return _keyStoreResource.toString();
539     }
540 
541     /**
542      * @param keyStorePath
543      *            The file or URL of the SSL Key store.
544      */
545     public void setKeyStorePath(String keyStorePath)
546     {
547         checkNotStarted();
548         try
549         {
550             _keyStoreResource = Resource.newResource(keyStorePath);
551         }
552         catch (MalformedURLException e)
553         {
554             throw new IllegalArgumentException(e);
555         }
556     }
557 
558     /**
559      * @return The provider of the key store
560      */
561     public String getKeyStoreProvider()
562     {
563         return _keyStoreProvider;
564     }
565 
566     /**
567      * @param keyStoreProvider
568      *            The provider of the key store
569      */
570     public void setKeyStoreProvider(String keyStoreProvider)
571     {
572         checkNotStarted();
573         _keyStoreProvider = keyStoreProvider;
574     }
575 
576     /**
577      * @return The type of the key store (default "JKS")
578      */
579     public String getKeyStoreType()
580     {
581         return (_keyStoreType);
582     }
583 
584     /**
585      * @param keyStoreType
586      *            The type of the key store (default "JKS")
587      */
588     public void setKeyStoreType(String keyStoreType)
589     {
590         checkNotStarted();
591         _keyStoreType = keyStoreType;
592     }
593 
594     /**
595      * @return Alias of SSL certificate for the connector
596      */
597     public String getCertAlias()
598     {
599         return _certAlias;
600     }
601 
602     /**
603      * Set the default certificate Alias.
604      * <p>This can be used if there are multiple non-SNI certificates
605      * to specify the certificate that should be used, or with SNI
606      * certificates to set a certificate to try if no others match
607      * </p>
608      * @param certAlias
609      *            Alias of SSL certificate for the connector
610      */
611     public void setCertAlias(String certAlias)
612     {
613         checkNotStarted();
614         _certAlias = certAlias;
615     }
616 
617     /**
618      * @param trustStorePath
619      *            The file name or URL of the trust store location
620      */
621     public void setTrustStorePath(String trustStorePath)
622     {
623         checkNotStarted();
624         try
625         {
626             _trustStoreResource = Resource.newResource(trustStorePath);
627         }
628         catch (MalformedURLException e)
629         {
630             throw new IllegalArgumentException(e);
631         }
632     }
633 
634     /**
635      * @return The provider of the trust store
636      */
637     public String getTrustStoreProvider()
638     {
639         return _trustStoreProvider;
640     }
641 
642     /**
643      * @param trustStoreProvider
644      *            The provider of the trust store
645      */
646     public void setTrustStoreProvider(String trustStoreProvider)
647     {
648         checkNotStarted();
649         _trustStoreProvider = trustStoreProvider;
650     }
651 
652     /**
653      * @return The type of the trust store (default "JKS")
654      */
655     public String getTrustStoreType()
656     {
657         return _trustStoreType;
658     }
659 
660     /**
661      * @param trustStoreType
662      *            The type of the trust store (default "JKS")
663      */
664     public void setTrustStoreType(String trustStoreType)
665     {
666         checkNotStarted();
667         _trustStoreType = trustStoreType;
668     }
669 
670     /**
671      * @return True if SSL needs client authentication.
672      * @see SSLEngine#getNeedClientAuth()
673      */
674     public boolean getNeedClientAuth()
675     {
676         return _needClientAuth;
677     }
678 
679     /**
680      * @param needClientAuth
681      *            True if SSL needs client authentication.
682      * @see SSLEngine#getNeedClientAuth()
683      */
684     public void setNeedClientAuth(boolean needClientAuth)
685     {
686         checkNotStarted();
687         _needClientAuth = needClientAuth;
688     }
689 
690     /**
691      * @return True if SSL wants client authentication.
692      * @see SSLEngine#getWantClientAuth()
693      */
694     public boolean getWantClientAuth()
695     {
696         return _wantClientAuth;
697     }
698 
699     /**
700      * @param wantClientAuth
701      *            True if SSL wants client authentication.
702      * @see SSLEngine#getWantClientAuth()
703      */
704     public void setWantClientAuth(boolean wantClientAuth)
705     {
706         checkNotStarted();
707         _wantClientAuth = wantClientAuth;
708     }
709 
710     /**
711      * @return true if SSL certificate has to be validated
712      */
713     public boolean isValidateCerts()
714     {
715         return _validateCerts;
716     }
717 
718     /**
719      * @param validateCerts
720      *            true if SSL certificates have to be validated
721      */
722     public void setValidateCerts(boolean validateCerts)
723     {
724         checkNotStarted();
725         _validateCerts = validateCerts;
726     }
727 
728     /**
729      * @return true if SSL certificates of the peer have to be validated
730      */
731     public boolean isValidatePeerCerts()
732     {
733         return _validatePeerCerts;
734     }
735 
736     /**
737      * @param validatePeerCerts
738      *            true if SSL certificates of the peer have to be validated
739      */
740     public void setValidatePeerCerts(boolean validatePeerCerts)
741     {
742         checkNotStarted();
743         _validatePeerCerts = validatePeerCerts;
744     }
745 
746     /**
747      * @param password
748      *            The password for the key store.  If null is passed and
749      *            a keystore is set, then
750      *            the {@link Password#getPassword(String, String, String)} is used to
751      *            obtain a password either from the {@value #PASSWORD_PROPERTY}
752      *            System property or by prompting for manual entry.
753      */
754     public void setKeyStorePassword(String password)
755     {
756         checkNotStarted();
757         if (password==null)
758         {
759             if (_keyStoreResource!=null)
760                 _keyStorePassword=Password.getPassword(PASSWORD_PROPERTY,null,null);
761             else
762                 _keyStorePassword=null;
763         }
764         else
765             _keyStorePassword = new Password(password);
766     }
767 
768     /**
769      * @param password
770      *            The password (if any) for the specific key within the key store.
771      *            If null is passed and the {@value #KEYPASSWORD_PROPERTY} system property is set,
772      *            then the {@link Password#getPassword(String, String, String)} is used to
773      *            obtain a password from the {@value #KEYPASSWORD_PROPERTY}  system property.
774      */
775     public void setKeyManagerPassword(String password)
776     {
777         checkNotStarted();
778         if (password==null)
779         {
780             if (System.getProperty(KEYPASSWORD_PROPERTY)!=null)
781                 _keyManagerPassword = Password.getPassword(KEYPASSWORD_PROPERTY,null,null);
782             else
783                 _keyManagerPassword = null;
784         }
785         else
786             _keyManagerPassword = new Password(password);
787     }
788 
789     /**
790      * @param password
791      *            The password for the trust store. If null is passed and a truststore is set
792      *            that is different from the keystore, then
793      *            the {@link Password#getPassword(String, String, String)} is used to
794      *            obtain a password either from the {@value #PASSWORD_PROPERTY}
795      *            System property or by prompting for manual entry.
796      */
797     public void setTrustStorePassword(String password)
798     {
799         checkNotStarted();
800         if (password==null)
801         {
802             // Do we need a truststore password?
803             if (_trustStoreResource!=null && !_trustStoreResource.equals(_keyStoreResource))
804                 _trustStorePassword = Password.getPassword(PASSWORD_PROPERTY,null,null);
805             else
806                 _trustStorePassword = null;
807         }
808         else
809             _trustStorePassword=new Password(password);
810     }
811 
812     /**
813      * @return The SSL provider name, which if set is passed to
814      * {@link SSLContext#getInstance(String, String)}
815      */
816     public String getProvider()
817     {
818         return _sslProvider;
819     }
820 
821     /**
822      * @param provider
823      *            The SSL provider name, which if set is passed to
824      *            {@link SSLContext#getInstance(String, String)}
825      */
826     public void setProvider(String provider)
827     {
828         checkNotStarted();
829         _sslProvider = provider;
830     }
831 
832     /**
833      * @return The SSL protocol (default "TLS") passed to
834      * {@link SSLContext#getInstance(String, String)}
835      */
836     public String getProtocol()
837     {
838         return _sslProtocol;
839     }
840 
841     /**
842      * @param protocol
843      *            The SSL protocol (default "TLS") passed to
844      *            {@link SSLContext#getInstance(String, String)}
845      */
846     public void setProtocol(String protocol)
847     {
848         checkNotStarted();
849         _sslProtocol = protocol;
850     }
851 
852     /**
853      * @return The algorithm name, which if set is passed to
854      * {@link SecureRandom#getInstance(String)} to obtain the {@link SecureRandom} instance passed to
855      * {@link SSLContext#init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], SecureRandom)}
856      */
857     public String getSecureRandomAlgorithm()
858     {
859         return _secureRandomAlgorithm;
860     }
861 
862     /**
863      * @param algorithm
864      *            The algorithm name, which if set is passed to
865      *            {@link SecureRandom#getInstance(String)} to obtain the {@link SecureRandom} instance passed to
866      *            {@link SSLContext#init(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], SecureRandom)}
867      */
868     public void setSecureRandomAlgorithm(String algorithm)
869     {
870         checkNotStarted();
871         _secureRandomAlgorithm = algorithm;
872     }
873 
874     /**
875      * @return The algorithm name (default "SunX509") used by the {@link KeyManagerFactory}
876      */
877     public String getSslKeyManagerFactoryAlgorithm()
878     {
879         return (_keyManagerFactoryAlgorithm);
880     }
881 
882     /**
883      * @param algorithm
884      *            The algorithm name (default "SunX509") used by the {@link KeyManagerFactory}
885      */
886     public void setSslKeyManagerFactoryAlgorithm(String algorithm)
887     {
888         checkNotStarted();
889         _keyManagerFactoryAlgorithm = algorithm;
890     }
891 
892     /**
893      * @return The algorithm name (default "SunX509") used by the {@link TrustManagerFactory}
894      */
895     public String getTrustManagerFactoryAlgorithm()
896     {
897         return (_trustManagerFactoryAlgorithm);
898     }
899 
900     /**
901      * @return True if all certificates should be trusted if there is no KeyStore or TrustStore
902      */
903     public boolean isTrustAll()
904     {
905         return _trustAll;
906     }
907 
908     /**
909      * @param trustAll True if all certificates should be trusted if there is no KeyStore or TrustStore
910      */
911     public void setTrustAll(boolean trustAll)
912     {
913         _trustAll = trustAll;
914         if(trustAll)
915             setEndpointIdentificationAlgorithm(null);
916     }
917 
918     /**
919      * @param algorithm
920      *            The algorithm name (default "SunX509") used by the {@link TrustManagerFactory}
921      *            Use the string "TrustAll" to install a trust manager that trusts all.
922      */
923     public void setTrustManagerFactoryAlgorithm(String algorithm)
924     {
925         checkNotStarted();
926         _trustManagerFactoryAlgorithm = algorithm;
927     }
928 
929     /**
930      * @return whether TLS renegotiation is allowed (true by default)
931      */
932     public boolean isRenegotiationAllowed()
933     {
934         return _renegotiationAllowed;
935     }
936 
937     /**
938      * @param renegotiationAllowed whether TLS renegotiation is allowed
939      */
940     public void setRenegotiationAllowed(boolean renegotiationAllowed)
941     {
942         _renegotiationAllowed = renegotiationAllowed;
943     }
944 
945     /**
946      * @return Path to file that contains Certificate Revocation List
947      */
948     public String getCrlPath()
949     {
950         return _crlPath;
951     }
952 
953     /**
954      * @param crlPath
955      *            Path to file that contains Certificate Revocation List
956      */
957     public void setCrlPath(String crlPath)
958     {
959         checkNotStarted();
960         _crlPath = crlPath;
961     }
962 
963     /**
964      * @return Maximum number of intermediate certificates in
965      * the certification path (-1 for unlimited)
966      */
967     public int getMaxCertPathLength()
968     {
969         return _maxCertPathLength;
970     }
971 
972     /**
973      * @param maxCertPathLength
974      *            maximum number of intermediate certificates in
975      *            the certification path (-1 for unlimited)
976      */
977     public void setMaxCertPathLength(int maxCertPathLength)
978     {
979         checkNotStarted();
980         _maxCertPathLength = maxCertPathLength;
981     }
982 
983     /**
984      * @return The SSLContext
985      */
986     public SSLContext getSslContext()
987     {
988         return isStarted()?_factory._context:_setContext;
989     }
990 
991     /**
992      * @param sslContext
993      *            Set a preconfigured SSLContext
994      */
995     public void setSslContext(SSLContext sslContext)
996     {
997         checkNotStarted();
998         _setContext = sslContext;
999     }
1000 
1001     /**
1002      * When set to "HTTPS" hostname verification will be enabled
1003      *
1004      * @param endpointIdentificationAlgorithm Set the endpointIdentificationAlgorithm
1005      */
1006     public void setEndpointIdentificationAlgorithm(String endpointIdentificationAlgorithm)
1007     {
1008         this._endpointIdentificationAlgorithm = endpointIdentificationAlgorithm;
1009     }
1010 
1011     /**
1012      * Override this method to provide alternate way to load a keystore.
1013      *
1014      * @param resource the resource to load the keystore from
1015      * @return the key store instance
1016      * @throws Exception if the keystore cannot be loaded
1017      */
1018     protected KeyStore loadKeyStore(Resource resource) throws Exception
1019     {
1020         return CertificateUtils.getKeyStore(resource, _keyStoreType, _keyStoreProvider,_keyStorePassword==null? null:_keyStorePassword.toString());
1021     }
1022 
1023     /**
1024      * Override this method to provide alternate way to load a truststore.
1025      *
1026      * @param resource the resource to load the truststore from
1027      * @return the key store instance
1028      * @throws Exception if the truststore cannot be loaded
1029      */
1030     protected KeyStore loadTrustStore(Resource resource) throws Exception
1031     {
1032         String type=_trustStoreType;
1033         String provider= _trustStoreProvider;
1034         String passwd=_trustStorePassword==null? null:_trustStorePassword.toString();
1035         if (resource==null || resource.equals(_keyStoreResource))
1036         {
1037             resource=_keyStoreResource;
1038             if (type==null)
1039                 type=_keyStoreType;
1040             if (provider==null)
1041                 provider= _keyStoreProvider;
1042             if (passwd==null)
1043                 passwd=_keyStorePassword==null? null:_keyStorePassword.toString();
1044         }
1045 
1046         return CertificateUtils.getKeyStore(resource,type,provider,passwd);
1047     }
1048 
1049     /**
1050      * Loads certificate revocation list (CRL) from a file.
1051      *
1052      * Required for integrations to be able to override the mechanism used to
1053      * load CRL in order to provide their own implementation.
1054      *
1055      * @param crlPath path of certificate revocation list file
1056      * @return Collection of CRL's
1057      * @throws Exception if the certificate revocation list cannot be loaded
1058      */
1059     protected Collection<? extends CRL> loadCRL(String crlPath) throws Exception
1060     {
1061         return CertificateUtils.loadCRL(crlPath);
1062     }
1063 
1064     protected KeyManager[] getKeyManagers(KeyStore keyStore) throws Exception
1065     {
1066         KeyManager[] managers = null;
1067 
1068         if (keyStore != null)
1069         {
1070             KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(_keyManagerFactoryAlgorithm);
1071             keyManagerFactory.init(keyStore,_keyManagerPassword == null?(_keyStorePassword == null?null:_keyStorePassword.toString().toCharArray()):_keyManagerPassword.toString().toCharArray());
1072             managers = keyManagerFactory.getKeyManagers();
1073 
1074             if (managers!=null)
1075             {
1076                 if (_certAlias != null)
1077                 {
1078                     for (int idx = 0; idx < managers.length; idx++)
1079                     {
1080                         if (managers[idx] instanceof X509ExtendedKeyManager)
1081                             managers[idx] = new AliasedX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx],_certAlias);
1082                     }
1083                 }
1084 
1085                 if (!_certHosts.isEmpty() || !_certWilds.isEmpty())
1086                 {
1087                     for (int idx = 0; idx < managers.length; idx++)
1088                     {
1089                         if (managers[idx] instanceof X509ExtendedKeyManager)
1090                             managers[idx]=new SniX509ExtendedKeyManager((X509ExtendedKeyManager)managers[idx]);
1091                     }
1092                 }
1093             }
1094         }
1095 
1096         LOG.debug("managers={} for {}",managers,this);
1097 
1098         return managers;
1099     }
1100 
1101     protected TrustManager[] getTrustManagers(KeyStore trustStore, Collection<? extends CRL> crls) throws Exception
1102     {
1103         TrustManager[] managers = null;
1104         if (trustStore != null)
1105         {
1106             // Revocation checking is only supported for PKIX algorithm
1107             if (_validatePeerCerts && _trustManagerFactoryAlgorithm.equalsIgnoreCase("PKIX"))
1108             {
1109                 PKIXBuilderParameters pbParams = new PKIXBuilderParameters(trustStore,new X509CertSelector());
1110 
1111                 // Set maximum certification path length
1112                 pbParams.setMaxPathLength(_maxCertPathLength);
1113 
1114                 // Make sure revocation checking is enabled
1115                 pbParams.setRevocationEnabled(true);
1116 
1117                 if (crls != null && !crls.isEmpty())
1118                 {
1119                     pbParams.addCertStore(CertStore.getInstance("Collection",new CollectionCertStoreParameters(crls)));
1120                 }
1121 
1122                 if (_enableCRLDP)
1123                 {
1124                     // Enable Certificate Revocation List Distribution Points (CRLDP) support
1125                     System.setProperty("com.sun.security.enableCRLDP","true");
1126                 }
1127 
1128                 if (_enableOCSP)
1129                 {
1130                     // Enable On-Line Certificate Status Protocol (OCSP) support
1131                     Security.setProperty("ocsp.enable","true");
1132 
1133                     if (_ocspResponderURL != null)
1134                     {
1135                         // Override location of OCSP Responder
1136                         Security.setProperty("ocsp.responderURL", _ocspResponderURL);
1137                     }
1138                 }
1139 
1140                 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_trustManagerFactoryAlgorithm);
1141                 trustManagerFactory.init(new CertPathTrustManagerParameters(pbParams));
1142 
1143                 managers = trustManagerFactory.getTrustManagers();
1144             }
1145             else
1146             {
1147                 TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(_trustManagerFactoryAlgorithm);
1148                 trustManagerFactory.init(trustStore);
1149 
1150                 managers = trustManagerFactory.getTrustManagers();
1151             }
1152         }
1153 
1154         return managers;
1155     }
1156 
1157     /**
1158      * Select protocols to be used by the connector
1159      * based on configured inclusion and exclusion lists
1160      * as well as enabled and supported protocols.
1161      * @param enabledProtocols Array of enabled protocols
1162      * @param supportedProtocols Array of supported protocols
1163      */
1164     public void selectProtocols(String[] enabledProtocols, String[] supportedProtocols)
1165     {
1166         Set<String> selected_protocols = new LinkedHashSet<>();
1167 
1168         // Set the starting protocols - either from the included or enabled list
1169         if (!_includeProtocols.isEmpty())
1170         {
1171             // Use only the supported included protocols
1172             for (String protocol : _includeProtocols)
1173             {
1174                 if(Arrays.asList(supportedProtocols).contains(protocol))
1175                     selected_protocols.add(protocol);
1176                 else
1177                     LOG.info("Protocol {} not supported in {}",protocol,Arrays.asList(supportedProtocols));
1178             }
1179         }
1180         else
1181             selected_protocols.addAll(Arrays.asList(enabledProtocols));
1182 
1183 
1184         // Remove any excluded protocols
1185         selected_protocols.removeAll(_excludeProtocols);
1186 
1187 
1188         if (selected_protocols.isEmpty())
1189             LOG.warn("No selected protocols from {}",Arrays.asList(supportedProtocols));
1190 
1191         _selectedProtocols = selected_protocols.toArray(new String[selected_protocols.size()]);
1192 
1193 
1194 
1195     }
1196 
1197     /**
1198      * Select cipher suites to be used by the connector
1199      * based on configured inclusion and exclusion lists
1200      * as well as enabled and supported cipher suite lists.
1201      * @param enabledCipherSuites Array of enabled cipher suites
1202      * @param supportedCipherSuites Array of supported cipher suites
1203      */
1204     protected void selectCipherSuites(String[] enabledCipherSuites, String[] supportedCipherSuites)
1205     {
1206         List<String> selected_ciphers = new ArrayList<>();
1207 
1208         // Set the starting ciphers - either from the included or enabled list
1209         if (_includeCipherSuites.isEmpty())
1210             selected_ciphers.addAll(Arrays.asList(enabledCipherSuites));
1211         else
1212             processIncludeCipherSuites(supportedCipherSuites, selected_ciphers);
1213 
1214         removeExcludedCipherSuites(selected_ciphers);
1215 
1216         if (selected_ciphers.isEmpty())
1217             LOG.warn("No supported ciphers from {}",Arrays.asList(supportedCipherSuites));
1218 
1219         if (_cipherComparator!=null)
1220         {
1221             if (LOG.isDebugEnabled())
1222                 LOG.debug("Sorting selected ciphers with {}",_cipherComparator);
1223             Collections.sort(selected_ciphers,_cipherComparator);
1224         }
1225 
1226         _selectedCipherSuites=selected_ciphers.toArray(new String[selected_ciphers.size()]);
1227     }
1228 
1229     protected void processIncludeCipherSuites(String[] supportedCipherSuites, List<String> selected_ciphers)
1230     {
1231         for (String cipherSuite : _includeCipherSuites)
1232         {
1233             Pattern p = Pattern.compile(cipherSuite);
1234             boolean added=false;
1235             for (String supportedCipherSuite : supportedCipherSuites)
1236             {
1237                 Matcher m = p.matcher(supportedCipherSuite);
1238                 if (m.matches())
1239                 {
1240                     added=true;
1241                     selected_ciphers.add(supportedCipherSuite);
1242                 }
1243 
1244             }
1245             if (!added)
1246                 LOG.info("No Cipher matching '{}' is supported",cipherSuite);
1247         }
1248     }
1249 
1250     protected void removeExcludedCipherSuites(List<String> selected_ciphers)
1251     {
1252         for (String excludeCipherSuite : _excludeCipherSuites)
1253         {
1254             Pattern excludeCipherPattern = Pattern.compile(excludeCipherSuite);
1255             for (Iterator<String> i=selected_ciphers.iterator();i.hasNext();)
1256             {
1257                 String selectedCipherSuite = i.next();
1258                 Matcher m = excludeCipherPattern.matcher(selectedCipherSuite);
1259                 if (m.matches())
1260                     i.remove();
1261             }
1262         }
1263     }
1264 
1265     /**
1266      * Check if the lifecycle has been started and throw runtime exception
1267      */
1268     protected void checkNotStarted()
1269     {
1270         if (isStarted())
1271             throw new IllegalStateException("Cannot modify configuration when "+getState());
1272     }
1273 
1274     /**
1275      * Check if the lifecycle has been started and throw runtime exception
1276      */
1277     protected void checkIsStarted()
1278     {
1279         if (!isStarted())
1280             throw new IllegalStateException("!STARTED: "+this);
1281     }
1282 
1283     /**
1284      * Check if the lifecycle has been started and throw runtime exception
1285      */
1286     protected void checkIsRunning()
1287     {
1288         if (!isRunning())
1289             throw new IllegalStateException("!RUNNING: "+this);
1290     }
1291 
1292     /**
1293      * @return true if CRL Distribution Points support is enabled
1294      */
1295     public boolean isEnableCRLDP()
1296     {
1297         return _enableCRLDP;
1298     }
1299 
1300     /** Enables CRL Distribution Points Support
1301      * @param enableCRLDP true - turn on, false - turns off
1302      */
1303     public void setEnableCRLDP(boolean enableCRLDP)
1304     {
1305         checkNotStarted();
1306         _enableCRLDP = enableCRLDP;
1307     }
1308 
1309     /**
1310      * @return true if On-Line Certificate Status Protocol support is enabled
1311      */
1312     public boolean isEnableOCSP()
1313     {
1314         return _enableOCSP;
1315     }
1316 
1317     /** Enables On-Line Certificate Status Protocol support
1318      * @param enableOCSP true - turn on, false - turn off
1319      */
1320     public void setEnableOCSP(boolean enableOCSP)
1321     {
1322         checkNotStarted();
1323         _enableOCSP = enableOCSP;
1324     }
1325 
1326     /**
1327      * @return Location of the OCSP Responder
1328      */
1329     public String getOcspResponderURL()
1330     {
1331         return _ocspResponderURL;
1332     }
1333 
1334     /** Set the location of the OCSP Responder.
1335      * @param ocspResponderURL location of the OCSP Responder
1336      */
1337     public void setOcspResponderURL(String ocspResponderURL)
1338     {
1339         checkNotStarted();
1340         _ocspResponderURL = ocspResponderURL;
1341     }
1342 
1343     /** Set the key store.
1344      * @param keyStore the key store to set
1345      */
1346     public void setKeyStore(KeyStore keyStore)
1347     {
1348         checkNotStarted();
1349         _setKeyStore = keyStore;
1350     }
1351 
1352     public KeyStore getKeyStore()
1353     {
1354         return isStarted()?_factory._keyStore:_setKeyStore;
1355     }
1356 
1357     /** Set the trust store.
1358      * @param trustStore the trust store to set
1359      */
1360     public void setTrustStore(KeyStore trustStore)
1361     {
1362         checkNotStarted();
1363         _setTrustStore = trustStore;
1364     }
1365 
1366     public KeyStore getTrustStore()
1367     {
1368         return isStarted()?_factory._trustStore:_setTrustStore;
1369     }
1370 
1371     /** Set the key store resource.
1372      * @param resource the key store resource to set
1373      */
1374     public void setKeyStoreResource(Resource resource)
1375     {
1376         checkNotStarted();
1377         _keyStoreResource=resource;
1378     }
1379 
1380     public Resource getKeyStoreResource()
1381     {
1382         return _keyStoreResource;
1383     }
1384 
1385     /** Set the trust store resource.
1386      * @param resource the trust store resource to set
1387      */
1388     public void setTrustStoreResource(Resource resource)
1389     {
1390         checkNotStarted();
1391         _trustStoreResource=resource;
1392     }
1393 
1394     public Resource getTrustStoreResource()
1395     {
1396         return _trustStoreResource;
1397     }
1398 
1399     /**
1400     * @return true if SSL Session caching is enabled
1401     */
1402     public boolean isSessionCachingEnabled()
1403     {
1404         return _sessionCachingEnabled;
1405     }
1406 
1407     /** Set the flag to enable SSL Session caching.
1408     * @param enableSessionCaching the value of the flag
1409     */
1410     public void setSessionCachingEnabled(boolean enableSessionCaching)
1411     {
1412         _sessionCachingEnabled = enableSessionCaching;
1413     }
1414 
1415     /** Get SSL session cache size.
1416      * @return SSL session cache size
1417      */
1418     public int getSslSessionCacheSize()
1419     {
1420         return _sslSessionCacheSize;
1421     }
1422 
1423     /** SEt SSL session cache size.
1424      * @param sslSessionCacheSize SSL session cache size to set
1425      */
1426     public void setSslSessionCacheSize(int sslSessionCacheSize)
1427     {
1428         _sslSessionCacheSize = sslSessionCacheSize;
1429     }
1430 
1431     /** Get SSL session timeout.
1432      * @return SSL session timeout
1433      */
1434     public int getSslSessionTimeout()
1435     {
1436         return _sslSessionTimeout;
1437     }
1438 
1439     /** Set SSL session timeout.
1440      * @param sslSessionTimeout SSL session timeout to set
1441      */
1442     public void setSslSessionTimeout(int sslSessionTimeout)
1443     {
1444         _sslSessionTimeout = sslSessionTimeout;
1445     }
1446 
1447 
1448     public SSLServerSocket newSslServerSocket(String host,int port,int backlog) throws IOException
1449     {
1450         checkIsStarted();
1451 
1452         SSLServerSocketFactory factory = _factory._context.getServerSocketFactory();
1453 
1454         SSLServerSocket socket =
1455             (SSLServerSocket) (host==null ?
1456                         factory.createServerSocket(port,backlog):
1457                         factory.createServerSocket(port,backlog,InetAddress.getByName(host)));
1458 
1459         if (getWantClientAuth())
1460             socket.setWantClientAuth(getWantClientAuth());
1461         if (getNeedClientAuth())
1462             socket.setNeedClientAuth(getNeedClientAuth());
1463 
1464         socket.setEnabledCipherSuites(_selectedCipherSuites);
1465         socket.setEnabledProtocols(_selectedProtocols);
1466 
1467         return socket;
1468     }
1469 
1470     public SSLSocket newSslSocket() throws IOException
1471     {
1472         checkIsStarted();
1473 
1474         SSLSocketFactory factory = _factory._context.getSocketFactory();
1475 
1476         SSLSocket socket = (SSLSocket)factory.createSocket();
1477 
1478         if (getWantClientAuth())
1479             socket.setWantClientAuth(getWantClientAuth());
1480         if (getNeedClientAuth())
1481             socket.setNeedClientAuth(getNeedClientAuth());
1482 
1483         socket.setEnabledCipherSuites(_selectedCipherSuites);
1484         socket.setEnabledProtocols(_selectedProtocols);
1485 
1486         return socket;
1487     }
1488 
1489     /**
1490      * Factory method for "scratch" {@link SSLEngine}s, usually only used for retrieving configuration
1491      * information such as the application buffer size or the list of protocols/ciphers.
1492      * <p>
1493      * This method should not be used for creating {@link SSLEngine}s that are used in actual socket
1494      * communication.
1495      *
1496      * @return a new, "scratch" {@link SSLEngine}
1497      */
1498     public SSLEngine newSSLEngine()
1499     {
1500         checkIsRunning();
1501         SSLEngine sslEngine=_factory._context.createSSLEngine();
1502         customize(sslEngine);
1503         return sslEngine;
1504     }
1505 
1506     /**
1507      * General purpose factory method for creating {@link SSLEngine}s, although creation of
1508      * {@link SSLEngine}s on the server-side should prefer {@link #newSSLEngine(InetSocketAddress)}.
1509      *
1510      * @param host the remote host
1511      * @param port the remote port
1512      * @return a new {@link SSLEngine}
1513      */
1514     public SSLEngine newSSLEngine(String host, int port)
1515     {
1516         checkIsStarted();
1517         SSLEngine sslEngine=isSessionCachingEnabled()
1518             ? _factory._context.createSSLEngine(host, port)
1519             : _factory._context.createSSLEngine();
1520         customize(sslEngine);
1521         return sslEngine;
1522     }
1523 
1524     /**
1525      * Server-side only factory method for creating {@link SSLEngine}s.
1526      * <p>
1527      * If the given {@code address} is null, it is equivalent to {@link #newSSLEngine()}, otherwise
1528      * {@link #newSSLEngine(String, int)} is called.
1529      * <p>
1530      * If {@link #getNeedClientAuth()} is {@code true}, then the host name is passed to
1531      * {@link #newSSLEngine(String, int)}, possibly incurring in a reverse DNS lookup, which takes time
1532      * and may hang the selector (since this method is usually called by the selector thread).
1533      * <p>
1534      * Otherwise, the host address is passed to {@link #newSSLEngine(String, int)} without DNS lookup
1535      * penalties.
1536      * <p>
1537      * Clients that wish to create {@link SSLEngine} instances must use {@link #newSSLEngine(String, int)}.
1538      *
1539      * @param address the remote peer address
1540      * @return a new {@link SSLEngine}
1541      */
1542     public SSLEngine newSSLEngine(InetSocketAddress address)
1543     {
1544         if (address == null)
1545             return newSSLEngine();
1546 
1547         boolean useHostName = getNeedClientAuth();
1548         String hostName = useHostName ? address.getHostName() : address.getAddress().getHostAddress();
1549         return newSSLEngine(hostName, address.getPort());
1550     }
1551 
1552     public void customize(SSLEngine sslEngine)
1553     {
1554         if (LOG.isDebugEnabled())
1555             LOG.debug("Customize {}",sslEngine);
1556 
1557         SSLParameters sslParams = sslEngine.getSSLParameters();
1558         sslParams.setEndpointIdentificationAlgorithm(_endpointIdentificationAlgorithm);
1559         sslParams.setUseCipherSuitesOrder(_useCipherSuitesOrder);
1560         if (!_certHosts.isEmpty() || !_certWilds.isEmpty())
1561         {
1562             if (LOG.isDebugEnabled())
1563                 LOG.debug("Enable SNI matching {}",sslEngine);
1564             sslParams.setSNIMatchers(Collections.singletonList((SNIMatcher)new AliasSNIMatcher()));
1565         }
1566         sslParams.setCipherSuites(_selectedCipherSuites);
1567         sslParams.setProtocols(_selectedProtocols);
1568 
1569         if (getWantClientAuth())
1570             sslParams.setWantClientAuth(true);
1571         if (getNeedClientAuth())
1572             sslParams.setNeedClientAuth(true);
1573 
1574         sslEngine.setSSLParameters(sslParams);
1575     }
1576 
1577     public static X509Certificate[] getCertChain(SSLSession sslSession)
1578     {
1579         try
1580         {
1581             Certificate[] javaxCerts=sslSession.getPeerCertificates();
1582             if (javaxCerts==null||javaxCerts.length==0)
1583                 return null;
1584 
1585             int length=javaxCerts.length;
1586             X509Certificate[] javaCerts=new X509Certificate[length];
1587 
1588             java.security.cert.CertificateFactory cf=java.security.cert.CertificateFactory.getInstance("X.509");
1589             for (int i=0; i<length; i++)
1590             {
1591                 byte bytes[]=javaxCerts[i].getEncoded();
1592                 ByteArrayInputStream stream=new ByteArrayInputStream(bytes);
1593                 javaCerts[i]=(X509Certificate)cf.generateCertificate(stream);
1594             }
1595 
1596             return javaCerts;
1597         }
1598         catch (SSLPeerUnverifiedException pue)
1599         {
1600             return null;
1601         }
1602         catch (Exception e)
1603         {
1604             LOG.warn(Log.EXCEPTION,e);
1605             return null;
1606         }
1607     }
1608 
1609     /**
1610      * Given the name of a TLS/SSL cipher suite, return an int representing it effective stream
1611      * cipher key strength. i.e. How much entropy material is in the key material being fed into the
1612      * encryption routines.
1613      *
1614      * <p>
1615      * This is based on the information on effective key lengths in RFC 2246 - The TLS Protocol
1616      * Version 1.0, Appendix C. CipherSuite definitions:
1617      *
1618      * <pre>
1619      *                         Effective
1620      *     Cipher       Type    Key Bits
1621      *
1622      *     NULL       * Stream     0
1623      *     IDEA_CBC     Block    128
1624      *     RC2_CBC_40 * Block     40
1625      *     RC4_40     * Stream    40
1626      *     RC4_128      Stream   128
1627      *     DES40_CBC  * Block     40
1628      *     DES_CBC      Block     56
1629      *     3DES_EDE_CBC Block    168
1630      * </pre>
1631      *
1632      * @param cipherSuite String name of the TLS cipher suite.
1633      * @return int indicating the effective key entropy bit-length.
1634      */
1635     public static int deduceKeyLength(String cipherSuite)
1636     {
1637         // Roughly ordered from most common to least common.
1638         if (cipherSuite == null)
1639             return 0;
1640         else if (cipherSuite.contains("WITH_AES_256_"))
1641             return 256;
1642         else if (cipherSuite.contains("WITH_RC4_128_"))
1643             return 128;
1644         else if (cipherSuite.contains("WITH_AES_128_"))
1645             return 128;
1646         else if (cipherSuite.contains("WITH_RC4_40_"))
1647             return 40;
1648         else if (cipherSuite.contains("WITH_3DES_EDE_CBC_"))
1649             return 168;
1650         else if (cipherSuite.contains("WITH_IDEA_CBC_"))
1651             return 128;
1652         else if (cipherSuite.contains("WITH_RC2_CBC_40_"))
1653             return 40;
1654         else if (cipherSuite.contains("WITH_DES40_CBC_"))
1655             return 40;
1656         else if (cipherSuite.contains("WITH_DES_CBC_"))
1657             return 56;
1658         else
1659             return 0;
1660     }
1661 
1662     @Override
1663     public String toString()
1664     {
1665         return String.format("%s@%x(%s,%s)",
1666                 getClass().getSimpleName(),
1667                 hashCode(),
1668                 _keyStoreResource,
1669                 _trustStoreResource);
1670     }
1671 
1672     protected class Factory
1673     {
1674         final KeyStore _keyStore;
1675         final KeyStore _trustStore;
1676         final SSLContext _context;
1677 
1678         public Factory(KeyStore keyStore, KeyStore trustStore, SSLContext context)
1679         {
1680             super();
1681             _keyStore = keyStore;
1682             _trustStore = trustStore;
1683             _context = context;
1684         }
1685 
1686         @Override
1687         public String toString()
1688         {
1689             return String.format("SslFactory@%x{%s}",System.identityHashCode(this),SslContextFactory.this);
1690         }
1691     }
1692 
1693     class AliasSNIMatcher extends SNIMatcher
1694     {
1695         private String _host;
1696         private X509 _x509;
1697 
1698         AliasSNIMatcher()
1699         {
1700             super(StandardConstants.SNI_HOST_NAME);
1701         }
1702 
1703         @Override
1704         public boolean matches(SNIServerName serverName)
1705         {
1706             if (LOG.isDebugEnabled())
1707                 LOG.debug("SNI matching for {}",serverName);
1708 
1709             if (serverName instanceof SNIHostName)
1710             {
1711                 String host = _host = ((SNIHostName)serverName).getAsciiName();
1712                 host=StringUtil.asciiToLowerCase(host);
1713 
1714                 // Try an exact match
1715                 _x509 = _certHosts.get(host);
1716 
1717                 // Else try an exact wild match
1718                 if (_x509==null)
1719                 {
1720                     _x509 = _certWilds.get(host);
1721 
1722                     // Else try an 1 deep wild match
1723                     if (_x509==null)
1724                     {
1725                         int dot=host.indexOf('.');
1726                         if (dot>=0)
1727                         {
1728                             String domain=host.substring(dot+1);
1729                             _x509 = _certWilds.get(domain);
1730                         }
1731                     }
1732                 }
1733 
1734                 if (LOG.isDebugEnabled())
1735                     LOG.debug("SNI matched {}->{}",host,_x509);
1736             }
1737             else
1738             {
1739                 if (LOG.isDebugEnabled())
1740                     LOG.debug("SNI no match for {}", serverName);
1741             }
1742 
1743             // Return true and allow the KeyManager to accept or reject when choosing a certificate.
1744             // If we don't have a SNI host, or didn't see any certificate aliases,
1745             // just say true as it will either somehow work or fail elsewhere.
1746             return true;
1747         }
1748 
1749         public String getHost()
1750         {
1751             return _host;
1752         }
1753 
1754         public X509 getX509()
1755         {
1756             return _x509;
1757         }
1758     }
1759 }