View Javadoc

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