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