1 package org.jivesoftware.openfire.keystore;
2 
3 import org.jivesoftware.openfire.XMPPServer;
4 import org.jivesoftware.openfire.container.BasicModule;
5 import org.jivesoftware.openfire.spi.ConnectionListener;
6 import org.jivesoftware.openfire.spi.ConnectionManagerImpl;
7 import org.jivesoftware.openfire.spi.ConnectionType;
8 import org.jivesoftware.util.CollectionUtils;
9 import org.jivesoftware.util.JiveGlobals;
10 import org.slf4j.Logger;
11 import org.slf4j.LoggerFactory;
12 
13 import java.io.File;
14 import java.io.IOException;
15 import java.nio.file.Path;
16 import java.util.*;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ConcurrentMap;
19 import java.util.stream.Collectors;
20 
21 /**
22  * A manager of certificate stores.
23  *
24  */
25 // TODO Code duplication should be reduced.
26 // TODO Allow changing the store type.
27 public class CertificateStoreManager extends BasicModule
28 {
29     private final static Logger Log = LoggerFactory.getLogger( CertificateStoreManager.class );
30 
31     private final ConcurrentMap<ConnectionType, CertificateStoreConfiguration> typeToTrustStore    = new ConcurrentHashMap<>();
32     private final ConcurrentMap<ConnectionType, CertificateStoreConfiguration> typeToIdentityStore = new ConcurrentHashMap<>();
33     private final ConcurrentMap<CertificateStoreConfiguration, IdentityStore>  identityStores      = new ConcurrentHashMap<>();
34     private final ConcurrentMap<CertificateStoreConfiguration, TrustStore>     trustStores         = new ConcurrentHashMap<>();
35 
36     private CertificateStoreWatcher storeWatcher;
37 
CertificateStoreManager( )38     public CertificateStoreManager( )
39     {
40         super( "Certificate Store Manager" );
41     }
42 
43     @Override
initialize( XMPPServer server )44     public synchronized void initialize( XMPPServer server )
45     {
46         super.initialize( server );
47 
48         storeWatcher = new CertificateStoreWatcher();
49 
50         for ( final ConnectionType type : ConnectionType.values() )
51         {
52             try
53             {
54                 Log.debug( "(identity store for connection type '{}') Initializing store...", type );
55                 final CertificateStoreConfiguration identityStoreConfiguration = getIdentityStoreConfiguration( type );
56                 if ( !identityStores.containsKey( identityStoreConfiguration ) )
57                 {
58                     final IdentityStore store = new IdentityStore( identityStoreConfiguration, false );
59                     identityStores.put( identityStoreConfiguration, store );
60                     storeWatcher.watch( store );
61                 }
62                 typeToIdentityStore.put( type, identityStoreConfiguration );
63             }
64             catch ( CertificateStoreConfigException | IOException e )
65             {
66                 Log.warn( "(identity store for connection type '{}') Unable to instantiate store ", type, e );
67             }
68 
69             try
70             {
71                 Log.debug( "(trust store for connection type '{}') Initializing store...", type );
72                 final CertificateStoreConfiguration trustStoreConfiguration = getTrustStoreConfiguration( type );
73                 if ( !trustStores.containsKey( trustStoreConfiguration ) )
74                 {
75                     final TrustStore store = new TrustStore( trustStoreConfiguration, false );
76                     trustStores.put( trustStoreConfiguration, store );
77                     storeWatcher.watch( store );
78                 }
79                 typeToTrustStore.put( type, trustStoreConfiguration );
80             }
81             catch ( CertificateStoreConfigException | IOException e )
82             {
83                 Log.warn( "(trust store for connection type '{}') Unable to instantiate store ", type, e );
84             }
85         }
86     }
87 
88     @Override
destroy()89     public synchronized void destroy()
90     {
91         storeWatcher.destroy();
92         typeToIdentityStore.clear();
93         typeToTrustStore.clear();
94         identityStores.clear();
95         trustStores.clear();
96         super.destroy();
97     }
98 
getIdentityStore( ConnectionType type )99     public IdentityStore getIdentityStore( ConnectionType type )
100     {
101         final CertificateStoreConfiguration configuration = typeToIdentityStore.get( type );
102         if (configuration == null) {
103             return null;
104         }
105         return identityStores.get( configuration );
106     }
107 
getTrustStore( ConnectionType type )108     public TrustStore getTrustStore( ConnectionType type )
109     {
110         final CertificateStoreConfiguration configuration = typeToTrustStore.get( type );
111         if (configuration == null) {
112             return null;
113         }
114         return trustStores.get( configuration );
115     }
116 
replaceIdentityStore( ConnectionType type, CertificateStoreConfiguration configuration, boolean createIfAbsent )117     public void replaceIdentityStore( ConnectionType type, CertificateStoreConfiguration configuration, boolean createIfAbsent ) throws CertificateStoreConfigException
118     {
119         if ( type == null)
120         {
121             throw new IllegalArgumentException( "Argument 'type' cannot be null." );
122         }
123         if ( configuration == null)
124         {
125             throw new IllegalArgumentException( "Argument 'configuration' cannot be null." );
126         }
127 
128         final CertificateStoreConfiguration oldConfig = typeToIdentityStore.get( type ); // can be null if persisted properties are invalid
129 
130         if ( oldConfig == null || !oldConfig.equals( configuration ) )
131         {
132             // If the new store is not already being used by any other type, it'll need to be registered.
133             if ( !identityStores.containsKey( configuration ) )
134             {
135                 // This constructor can throw an exception. If it does, the state of the manager should not have already changed.
136                 final IdentityStore store = new IdentityStore( configuration, createIfAbsent );
137                 identityStores.put( configuration, store );
138                 storeWatcher.watch( store );
139             }
140 
141             typeToIdentityStore.put( type, configuration );
142 
143 
144             // If the old store is not used by any other type, it can be shut down.
145             if ( oldConfig != null && !typeToIdentityStore.containsValue( oldConfig ) )
146             {
147                 final IdentityStore store = identityStores.remove( oldConfig );
148                 if ( store != null )
149                 {
150                     storeWatcher.unwatch( store );
151                 }
152             }
153 
154             // Update all connection listeners that were using the old configuration.
155             final ConnectionManagerImpl connectionManager = ((ConnectionManagerImpl) XMPPServer.getInstance().getConnectionManager());
156             for ( ConnectionListener connectionListener : connectionManager.getListeners( type ) ) {
157                 try {
158                     connectionListener.setIdentityStoreConfiguration( configuration );
159                 } catch ( RuntimeException e ) {
160                     Log.warn( "An exception occurred while trying to update the identity store configuration for connection type '" + type + "'", e );
161                 }
162             }
163         }
164 
165         // Always store the new configuration in properties, to make sure that we override a potential fallback.
166         JiveGlobals.setProperty( type.getPrefix() + "keystore", configuration.getFile().getPath() ); // FIXME ensure that this is relative to Openfire home!
167         JiveGlobals.setProperty( type.getPrefix() + "keypass", new String( configuration.getPassword() ), true );
168     }
169 
replaceTrustStore( ConnectionType type, CertificateStoreConfiguration configuration, boolean createIfAbsent )170     public void replaceTrustStore( ConnectionType type, CertificateStoreConfiguration configuration, boolean createIfAbsent ) throws CertificateStoreConfigException
171     {
172         if ( type == null)
173         {
174             throw new IllegalArgumentException( "Argument 'type' cannot be null." );
175         }
176         if ( configuration == null)
177         {
178             throw new IllegalArgumentException( "Argument 'configuration' cannot be null." );
179         }
180 
181         final CertificateStoreConfiguration oldConfig = typeToTrustStore.get( type ); // can be null if persisted properties are invalid
182 
183         if ( oldConfig == null || !oldConfig.equals( configuration ) )
184         {
185             // If the new store is not already being used by any other type, it'll need to be registered.
186             if ( !trustStores.containsKey( configuration ) )
187             {
188                 // This constructor can throw an exception. If it does, the state of the manager should not have already changed.
189                 final TrustStore store = new TrustStore( configuration, createIfAbsent );
190                 trustStores.put( configuration, store );
191                 storeWatcher.watch( store );
192             }
193 
194             typeToTrustStore.put( type, configuration );
195 
196 
197             // If the old store is not used by any other type, it can be shut down.
198             if ( oldConfig != null && !typeToTrustStore.containsValue( oldConfig ) )
199             {
200                 final TrustStore store = trustStores.remove( oldConfig );
201                 if ( store != null )
202                 {
203                     storeWatcher.unwatch( store );
204                 }
205             }
206 
207             // Update all connection listeners that were using the old configuration.
208             final ConnectionManagerImpl connectionManager = ((ConnectionManagerImpl) XMPPServer.getInstance().getConnectionManager());
209             for ( ConnectionListener connectionListener : connectionManager.getListeners( type ) ) {
210                 try {
211                     connectionListener.setTrustStoreConfiguration( configuration );
212                 } catch ( RuntimeException e ) {
213                     Log.warn( "An exception occurred while trying to update the trust store configuration for connection type '" + type + "'", e );
214                 }
215             }
216 
217         }
218 
219         // Always store the new configuration in properties, to make sure that we override a potential fallback.
220         JiveGlobals.setProperty( type.getPrefix() + "truststore", configuration.getFile().getPath() ); // FIXME ensure that this is relative to Openfire home!
221         JiveGlobals.setProperty( type.getPrefix() + "trustpass", new String( configuration.getPassword() ), true  );
222     }
223 
getIdentityStoreConfiguration( ConnectionType type )224     public CertificateStoreConfiguration getIdentityStoreConfiguration( ConnectionType type ) throws IOException
225     {
226         // Getting individual properties might use fallbacks. It is assumed (but not asserted) that each property value
227         // is obtained from the same connectionType (which is either the argument to this method, or one of its
228         // fallbacks.
229         final String keyStoreType = getIdentityStoreType( type );
230         final String password = getIdentityStorePassword( type );
231         final String location = getIdentityStoreLocation( type );
232         final String backupDirectory = getIdentityStoreBackupDirectory( type );
233         final File file = canonicalize( location );
234         final File dir = canonicalize( backupDirectory );
235 
236         return new CertificateStoreConfiguration( keyStoreType, file, password.toCharArray(), dir );
237     }
238 
getTrustStoreConfiguration( ConnectionType type )239     public CertificateStoreConfiguration getTrustStoreConfiguration( ConnectionType type ) throws IOException
240     {
241         // Getting individual properties might use fallbacks. It is assumed (but not asserted) that each property value
242         // is obtained from the same connectionType (which is either the argument to this method, or one of its
243         // fallbacks.
244         final String keyStoreType = getTrustStoreType( type );
245         final String password = getTrustStorePassword( type );
246         final String location = getTrustStoreLocation( type );
247         final String backupDirectory = getTrustStoreBackupDirectory( type );
248         final File file = canonicalize( location );
249         final File dir = canonicalize( backupDirectory );
250 
251         return new CertificateStoreConfiguration( keyStoreType, file, password.toCharArray(), dir );
252     }
253 
254     /**
255      * Creates a backup of all files that back any of the certificate stores.
256      *
257      * Each certificate store can be configured to use a distinct file, as well as use a distinct backup location.
258      * In practise, there will be a lot of overlap. This implementation creates a backup (by copying the file) for
259      * each unique file/backup-location combination in the collection of all certificate stores.
260      * @return the paths the store was backed up to
261      * @throws IOException if the store could not be backed up
262      */
backup()263     public Collection<Path> backup() throws IOException
264     {
265         // Create a collection that holds all of the certificate stores.
266         final Collection<CertificateStore> allStores = new ArrayList<>();
267         allStores.addAll( identityStores.values() );
268         allStores.addAll( trustStores.values() );
269 
270         // Extract the set of unique file/backup-directory combinations. This prevents Openfire from creating duplicate backup files.
271         final Set<CertificateStore> unique = allStores.stream().filter(
272             CollectionUtils.distinctByKey(
273                 store -> store.getConfiguration().getFile().getAbsolutePath() + "|" + store.configuration.backupDirectory.getAbsolutePath() ) )
274             .collect( Collectors.toSet() );
275 
276         // Trigger a backup for each of the unique combinations, and record the unique backup locations
277         final Collection<Path> backups = unique.stream()
278             .map( CertificateStore::backup )
279             .filter( Objects::nonNull )
280             .distinct()
281             .sorted()
282             .collect( Collectors.toList() );
283 
284         // If the number of backups is smaller than the number of unique file/backup-directory combinations, something went wrong!
285         if ( unique.size() != backups.size() ) {
286             throw new IOException( "Unable to create (all) backups!" );
287         }
288 
289         return backups;
290     }
291 
292     /**
293      * The KeyStore type (jks, jceks, pkcs12, etc) for the trust store for connections of a particular type.
294      *
295      * @param type the connection type
296      * @return a store type (never null).
297      * @see <a href="https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyStore">Java Cryptography Architecture Standard Algorithm Name Documentation</a>
298      */
getTrustStoreType( ConnectionType type )299     public static String getTrustStoreType( ConnectionType type )
300     {
301         final String propertyName = type.getPrefix() + "trustStoreType";
302         final String defaultValue = getKeyStoreType( type );
303 
304         if ( type.getFallback() == null )
305         {
306             return JiveGlobals.getProperty( propertyName, defaultValue ).trim();
307         }
308         else
309         {
310             return JiveGlobals.getProperty( propertyName, getTrustStoreType( type.getFallback() ) ).trim();
311         }
312     }
313 
setTrustStoreType( ConnectionType type, String keyStoreType )314     static void setTrustStoreType( ConnectionType type, String keyStoreType )
315     {
316         // Always set the property explicitly even if it appears the equal to the old value (the old value might be a fallback value).
317         JiveGlobals.setProperty( type.getPrefix() + "trustStoreType", keyStoreType );
318 
319         final String oldKeyStoreType = getTrustStoreType( type );
320         if ( oldKeyStoreType.equals( keyStoreType ) )
321         {
322             Log.debug( "Ignoring Trust Store type change request (to '{}'): listener already in this state.", keyStoreType );
323             return;
324         }
325 
326         Log.debug( "Changing Trust Store type from '{}' to '{}'.", oldKeyStoreType, keyStoreType );
327         // TODO shouldn't this do something?
328     }
329 
330     /**
331      * The KeyStore type (jks, jceks, pkcs12, etc) for the identity store for connections of a particular type.
332      *
333      * @param type the connection type
334      * @return a store type (never null).
335      * @see <a href="https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyStore">Java Cryptography Architecture Standard Algorithm Name Documentation</a>
336      */
getIdentityStoreType( ConnectionType type )337     public static String getIdentityStoreType( ConnectionType type )
338     {
339         final String propertyName = type.getPrefix() + "identityStoreType";
340         final String defaultValue = getKeyStoreType( type );
341 
342         if ( type.getFallback() == null )
343         {
344             return JiveGlobals.getProperty( propertyName, defaultValue ).trim();
345         }
346         else
347         {
348             return JiveGlobals.getProperty( propertyName, getIdentityStoreType( type.getFallback() ) ).trim();
349         }
350     }
351 
setIdentityStoreType( ConnectionType type, String keyStoreType )352     static void setIdentityStoreType( ConnectionType type, String keyStoreType )
353     {
354         // Always set the property explicitly even if it appears the equal to the old value (the old value might be a fallback value).
355         JiveGlobals.setProperty( type.getPrefix() + "identityStoreType", keyStoreType );
356 
357         final String oldKeyStoreType = getIdentityStoreType( type );
358         if ( oldKeyStoreType.equals( keyStoreType ) )
359         {
360             Log.debug( "Ignoring Identity Store type change request (to '{}'): listener already in this state.", keyStoreType );
361             return;
362         }
363 
364         Log.debug( "Changing Identity Store type from '{}' to '{}'.", oldKeyStoreType, keyStoreType );
365         // TODO shouldn't this do something?
366     }
367 
368     /**
369      * The KeyStore type (jks, jceks, pkcs12, etc) for the identity and trust store for connections of a particular type.
370      *
371      * @param type the connection type
372      * @return a store type (never null).
373      * @see <a href="https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#KeyStore">Java Cryptography Architecture Standard Algorithm Name Documentation</a>
374      * @deprecated use either {@link #getTrustStoreType(ConnectionType)} or {@link #getIdentityStoreType(ConnectionType)}
375      */
376     @Deprecated
getKeyStoreType( ConnectionType type )377     public static String getKeyStoreType( ConnectionType type )
378     {
379         final String propertyName = type.getPrefix() + "storeType";
380         final String defaultValue = "jks";
381 
382         if ( type.getFallback() == null )
383         {
384             return JiveGlobals.getProperty( propertyName, defaultValue ).trim();
385         }
386         else
387         {
388             return JiveGlobals.getProperty( propertyName, getKeyStoreType( type.getFallback() ) ).trim();
389         }
390     }
391 
setKeyStoreType( ConnectionType type, String keyStoreType )392     static void setKeyStoreType( ConnectionType type, String keyStoreType )
393     {
394         // Always set the property explicitly even if it appears the equal to the old value (the old value might be a fallback value).
395         JiveGlobals.setProperty( type.getPrefix() + "storeType", keyStoreType );
396 
397         final String oldKeyStoreType = getKeyStoreType( type );
398         if ( oldKeyStoreType.equals( keyStoreType ) )
399         {
400             Log.debug( "Ignoring KeyStore type change request (to '{}'): listener already in this state.", keyStoreType );
401             return;
402         }
403 
404         Log.debug( "Changing KeyStore type from '{}' to '{}'.", oldKeyStoreType, keyStoreType );
405         // TODO shouldn't this do something?
406     }
407 
408     /**
409      * The password of the identity store for connection created by this listener.
410      *
411      * @return a password (never null).
412      */
getIdentityStorePassword( ConnectionType type )413     static String getIdentityStorePassword( ConnectionType type )
414     {
415         final String propertyName = type.getPrefix() + "keypass";
416         final String defaultValue = "changeit";
417 
418         if ( type.getFallback() == null )
419         {
420             return JiveGlobals.getProperty( propertyName, defaultValue ).trim();
421         }
422         else
423         {
424             return JiveGlobals.getProperty( propertyName, getIdentityStorePassword( type.getFallback() ) ).trim();
425         }
426     }
427 
428     /**
429      * The password of the trust store for connections created by this listener.
430      *
431      * @return a password (never null).
432      */
getTrustStorePassword( ConnectionType type )433     static String getTrustStorePassword( ConnectionType type )
434     {
435         final String propertyName = type.getPrefix() + "trustpass";
436         final String defaultValue = "changeit";
437 
438         if ( type.getFallback() == null )
439         {
440             return JiveGlobals.getProperty( propertyName, defaultValue ).trim();
441         }
442         else
443         {
444             return JiveGlobals.getProperty( propertyName, getTrustStorePassword( type.getFallback() ) ).trim();
445         }
446     }
447 
448     /**
449      * The location (relative to OPENFIRE_HOME) of the identity store for connections created by this listener.
450      *
451      * @return a path (never null).
452      */
getIdentityStoreLocation( ConnectionType type )453     static String getIdentityStoreLocation( ConnectionType type )
454     {
455         final String propertyName = type.getPrefix()  + "keystore";
456         final String defaultValue = "resources" + File.separator + "security" + File.separator + "keystore";
457 
458         if ( type.getFallback() == null )
459         {
460             return JiveGlobals.getProperty( propertyName, defaultValue ).trim();
461         }
462         else
463         {
464             return JiveGlobals.getProperty( propertyName, getIdentityStoreLocation( type.getFallback() ) ).trim();
465         }
466     }
467 
468     /**
469      * The location (relative to OPENFIRE_HOME) of the trust store for connections created by this listener.
470      *
471      * @return a path (never null).
472      */
getTrustStoreLocation( ConnectionType type )473     static String getTrustStoreLocation( ConnectionType type )
474     {
475         final String propertyName = type.getPrefix()  + "truststore";
476         final String defaultValue;
477 
478         // OF-1191: For client-oriented connection types, Openfire traditionally uses a different truststore.
479         if ( type.isClientOriented() )
480         {
481             defaultValue = "resources" + File.separator + "security" + File.separator + "client.truststore";
482         }
483         else
484         {
485             defaultValue = "resources" + File.separator + "security" + File.separator + "truststore";
486         }
487 
488         if ( type.getFallback() == null )
489         {
490             return JiveGlobals.getProperty( propertyName, defaultValue ).trim();
491         }
492         else
493         {
494             return JiveGlobals.getProperty( propertyName, getTrustStoreLocation( type.getFallback() ) ).trim();
495         }
496     }
497 
498     /**
499      * The location (relative to OPENFIRE_HOME) of the directory that holds backups for identity stores.
500      *
501      * @param type the connection type
502      * @return a path (never null).
503      */
getIdentityStoreBackupDirectory( ConnectionType type )504     public static String getIdentityStoreBackupDirectory( ConnectionType type )
505     {
506         final String propertyName = type.getPrefix()  + "backup.keystore.location";
507         final String defaultValue = "resources" + File.separator + "security" + File.separator + "archive" + File.separator;
508 
509         if ( type.getFallback() == null )
510         {
511             return JiveGlobals.getProperty( propertyName, defaultValue ).trim();
512         }
513         else
514         {
515             return JiveGlobals.getProperty( propertyName, getIdentityStoreBackupDirectory( type.getFallback() ) ).trim();
516         }
517     }
518 
519     /**
520      * The location (relative to OPENFIRE_HOME) of the directory that holds backups for trust stores.
521      *
522      * @param type the connection type
523      * @return a path (never null).
524      */
getTrustStoreBackupDirectory( ConnectionType type )525     public static String getTrustStoreBackupDirectory( ConnectionType type )
526     {
527         final String propertyName = type.getPrefix()  + "backup.truststore.location";
528         final String defaultValue = "resources" + File.separator + "security" + File.separator + "archive" + File.separator;
529 
530         if ( type.getFallback() == null )
531         {
532             return JiveGlobals.getProperty( propertyName, defaultValue ).trim();
533         }
534         else
535         {
536             return JiveGlobals.getProperty( propertyName, getTrustStoreBackupDirectory( type.getFallback() ) ).trim();
537         }
538     }
539 
540     /**
541      * Canonicalizes a path. When the provided path is a relative path, it is interpreted as to be relative to the home
542      * directory of Openfire.
543      *
544      * @param path A path (cannot be null)
545      * @return A canonical representation of the path.
546      */
canonicalize( String path )547     static File canonicalize( String path ) throws IOException
548     {
549         File file = new File( path );
550         if (!file.isAbsolute()) {
551             file = new File( JiveGlobals.getHomeDirectory() + File.separator + path );
552         }
553 
554         return file;
555     }
556 
557     /**
558      * Checks if Openfire is configured to use the same set of three keystore files for all connection types (one
559      * identity store, and two trust stores - one for client-based connections, and one for server/component-based
560      * connections).
561      *
562      * This method will return 'false' when running Openfire without changes to its default keystore configuration. If
563      * changes are made to use different keystores for at least one connection type, this method returns 'true'.
564      *
565      * @return true if Openfire is using different keystores based on the type of connection, false when running with the default store configuration.
566      * @throws IOException if there was an IO error
567      */
usesDistinctConfigurationForEachType()568     public boolean usesDistinctConfigurationForEachType() throws IOException
569     {
570         CertificateStoreConfiguration identityStoreConfiguration = null;
571         CertificateStoreConfiguration c2sTrustStoreConfiguration = null;
572         CertificateStoreConfiguration s2sTrustStoreConfiguration = null;
573         for ( ConnectionType connectionType : ConnectionType.values() )
574         {
575             // Identity stores
576             if ( identityStoreConfiguration == null )
577             {
578                 identityStoreConfiguration = getIdentityStoreConfiguration( connectionType );
579             }
580             if ( !identityStoreConfiguration.equals( getIdentityStoreConfiguration( connectionType ) ) )
581             {
582                 return true;
583             }
584 
585             // Client-to-Server trust stores
586             if ( connectionType.isClientOriented() )
587             {
588                 if ( c2sTrustStoreConfiguration == null )
589                 {
590                     c2sTrustStoreConfiguration = getTrustStoreConfiguration( connectionType );
591                 }
592                 if ( !c2sTrustStoreConfiguration.equals( getTrustStoreConfiguration( connectionType ) ) )
593                 {
594                     return true;
595                 }
596             }
597             else
598             // Server-to-Server trust stores (includes component connections)
599             {
600                 if ( s2sTrustStoreConfiguration == null )
601                 {
602                     s2sTrustStoreConfiguration = getTrustStoreConfiguration( connectionType );
603                 }
604                 if ( !s2sTrustStoreConfiguration.equals( getTrustStoreConfiguration( connectionType ) ) )
605                 {
606                     return true;
607                 }
608             }
609         }
610 
611         return false;
612     }
613 }
614