001    /*
002     * Copyright 2008-2015 UnboundID Corp.
003     * All Rights Reserved.
004     */
005    /*
006     * Copyright (C) 2008-2015 UnboundID Corp.
007     *
008     * This program is free software; you can redistribute it and/or modify
009     * it under the terms of the GNU General Public License (GPLv2 only)
010     * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011     * as published by the Free Software Foundation.
012     *
013     * This program is distributed in the hope that it will be useful,
014     * but WITHOUT ANY WARRANTY; without even the implied warranty of
015     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016     * GNU General Public License for more details.
017     *
018     * You should have received a copy of the GNU General Public License
019     * along with this program; if not, see <http://www.gnu.org/licenses>.
020     */
021    package com.unboundid.util.ssl;
022    
023    
024    
025    import java.io.IOException;
026    import java.lang.reflect.Method;
027    import java.net.Socket;
028    import java.security.GeneralSecurityException;
029    import java.util.ArrayList;
030    import java.util.Arrays;
031    import java.util.Collection;
032    import java.util.Collections;
033    import java.util.HashSet;
034    import java.util.Iterator;
035    import java.util.Set;
036    import java.util.StringTokenizer;
037    import java.util.concurrent.atomic.AtomicReference;
038    import javax.net.ssl.KeyManager;
039    import javax.net.ssl.SSLContext;
040    import javax.net.ssl.SSLSocket;
041    import javax.net.ssl.SSLSocketFactory;
042    import javax.net.ssl.SSLServerSocketFactory;
043    import javax.net.ssl.TrustManager;
044    
045    import com.unboundid.ldap.sdk.LDAPException;
046    import com.unboundid.ldap.sdk.ResultCode;
047    import com.unboundid.util.Debug;
048    import com.unboundid.util.StaticUtils;
049    
050    import static com.unboundid.util.Validator.*;
051    import static com.unboundid.util.ssl.SSLMessages.*;
052    
053    
054    
055    /**
056     * This class provides a simple interface for creating {@code SSLContext} and
057     * {@code SSLSocketFactory} instances, which may be used to create SSL-based
058     * connections, or secure existing connections with StartTLS.
059     * <BR><BR>
060     * <H2>Example 1</H2>
061     * The following example demonstrates the use of the SSL helper to create an
062     * SSL-based LDAP connection that will blindly trust any certificate that the
063     * server presents.  Using the {@code TrustAllTrustManager} is only recommended
064     * for testing purposes, since blindly trusting any certificate is not secure.
065     * <PRE>
066     * // Create an SSLUtil instance that is configured to trust any certificate,
067     * // and use it to create a socket factory.
068     * SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
069     * SSLSocketFactory sslSocketFactory = sslUtil.createSSLSocketFactory();
070     *
071     * // Establish a secure connection using the socket factory.
072     * LDAPConnection connection = new LDAPConnection(sslSocketFactory);
073     * connection.connect(serverAddress, serverSSLPort);
074     *
075     * // Process operations using the connection....
076     * RootDSE rootDSE = connection.getRootDSE();
077     *
078     * connection.close();
079     * </PRE>
080     * <BR>
081     * <H2>Example 2</H2>
082     * The following example demonstrates the use of the SSL helper to create a
083     * non-secure LDAP connection and then use the StartTLS extended operation to
084     * secure it.  It will use a trust store to determine whether to trust the
085     * server certificate.
086     * <PRE>
087     * // Establish a non-secure connection to the server.
088     * LDAPConnection connection = new LDAPConnection(serverAddress, serverPort);
089     *
090     * // Create an SSLUtil instance that is configured to trust certificates in
091     * // a specified trust store file, and use it to create an SSLContext that
092     * // will be used for StartTLS processing.
093     * SSLUtil sslUtil = new SSLUtil(new TrustStoreTrustManager(trustStorePath));
094     * SSLContext sslContext = sslUtil.createSSLContext();
095     *
096     * // Use the StartTLS extended operation to secure the connection.
097     * StartTLSExtendedRequest startTLSRequest =
098     *      new StartTLSExtendedRequest(sslContext);
099     * ExtendedResult startTLSResult;
100     * try
101     * {
102     *   startTLSResult = connection.processExtendedOperation(startTLSRequest);
103     * }
104     * catch (LDAPException le)
105     * {
106     *   startTLSResult = new ExtendedResult(le);
107     * }
108     * LDAPTestUtils.assertResultCodeEquals(startTLSResult, ResultCode.SUCCESS);
109     *
110     * // Process operations using the connection....
111     * RootDSE rootDSE = connection.getRootDSE();
112     *
113     * connection.close();
114     * </PRE>
115     */
116    public final class SSLUtil
117    {
118      /**
119       * The name of the system property that can be used to specify the initial
120       * value for the default SSL protocol that should be used.  If this is not
121       * set, then the default SSL protocol will be dynamically determined.  This
122       * can be overridden via the {@code setDefaultSSLProtocol(String)} method.
123       */
124      public static final String PROPERTY_DEFAULT_SSL_PROTOCOL =
125           "com.unboundid.util.SSLUtil.defaultSSLProtocol";
126    
127    
128    
129      /**
130       * The name of the system property that can be used to provide the initial
131       * set of enabled SSL protocols that should be used, as a comma-delimited
132       * list.  If this is not set, then the enabled SSL protocols will be
133       * dynamically determined.  This can be overridden via the
134       * {@code setEnabledSSLProtocols(java.util.Collection)} method.
135       */
136      public static final String PROPERTY_ENABLED_SSL_PROTOCOLS =
137           "com.unboundid.util.SSLUtil.enabledSSLProtocols";
138    
139    
140    
141      /**
142       * The default protocol string that will be used to create SSL contexts when
143       * no explicit protocol is specified.
144       */
145      private static final AtomicReference<String> DEFAULT_SSL_PROTOCOL =
146           new AtomicReference<String>("TLSv1");
147    
148    
149    
150      /**
151       * The default set of SSL protocols that will be enabled for use if available
152       * for SSL sockets created within the LDAP SDK.
153       */
154      private static final AtomicReference<Set<String>> ENABLED_SSL_PROTOCOLS =
155           new AtomicReference<Set<String>>();
156    
157    
158    
159      static
160      {
161        configureSSLDefaults();
162      }
163    
164    
165    
166      // The set of key managers to be used.
167      private final KeyManager[] keyManagers;
168    
169      // The set of trust managers to be used.
170      private final TrustManager[] trustManagers;
171    
172    
173    
174      /**
175       * Creates a new SSLUtil instance that will not have a custom key manager or
176       * trust manager.  It will not be able to provide a certificate to the server
177       * if one is requested, and it will only trust certificates signed by a
178       * predefined set of authorities.
179       */
180      public SSLUtil()
181      {
182        keyManagers   = null;
183        trustManagers = null;
184      }
185    
186    
187    
188      /**
189       * Creates a new SSLUtil instance that will use the provided trust manager to
190       * determine whether to trust server certificates presented to the client.
191       * It will not be able to provide a certificate to the server if one is
192       * requested.
193       *
194       * @param  trustManager  The trust manager to use to determine whether to
195       *                       trust server certificates presented to the client.
196       *                       It may be {@code null} if the default set of trust
197       *                       managers should be used.
198       */
199      public SSLUtil(final TrustManager trustManager)
200      {
201        keyManagers = null;
202    
203        if (trustManager == null)
204        {
205          trustManagers = null;
206        }
207        else
208        {
209          trustManagers = new TrustManager[] { trustManager };
210        }
211      }
212    
213    
214    
215      /**
216       * Creates a new SSLUtil instance that will use the provided trust managers
217       * to determine whether to trust server certificates presented to the client.
218       * It will not be able to provide a certificate to the server if one is
219       * requested.
220       *
221       * @param  trustManagers  The set of trust managers to use to determine
222       *                        whether to trust server certificates presented to
223       *                        the client.  It may be {@code null} or empty if the
224       *                        default set of trust managers should be used.
225       */
226      public SSLUtil(final TrustManager[] trustManagers)
227      {
228        keyManagers = null;
229    
230        if ((trustManagers == null) || (trustManagers.length == 0))
231        {
232          this.trustManagers = null;
233        }
234        else
235        {
236          this.trustManagers = trustManagers;
237        }
238      }
239    
240    
241    
242      /**
243       * Creates a new SSLUtil instance that will use the provided key manager to
244       * obtain certificates to present to the server, and the provided trust
245       * manager to determine whether to trust server certificates presented to the
246       * client.
247       *
248       * @param  keyManager    The key manager to use to obtain certificates to
249       *                       present to the server if requested.  It may be
250       *                       {@code null} if no client certificates will be
251       *                       required or should be provided.
252       * @param  trustManager  The trust manager to use to determine whether to
253       *                       trust server certificates presented to the client.
254       *                       It may be {@code null} if the default set of trust
255       *                       managers should be used.
256       */
257      public SSLUtil(final KeyManager keyManager, final TrustManager trustManager)
258      {
259        if (keyManager == null)
260        {
261          keyManagers = null;
262        }
263        else
264        {
265          keyManagers = new KeyManager[] { keyManager };
266        }
267    
268        if (trustManager == null)
269        {
270          trustManagers = null;
271        }
272        else
273        {
274          trustManagers = new TrustManager[] { trustManager };
275        }
276      }
277    
278    
279    
280      /**
281       * Creates a new SSLUtil instance that will use the provided key managers to
282       * obtain certificates to present to the server, and the provided trust
283       * managers to determine whether to trust server certificates presented to the
284       * client.
285       *
286       * @param  keyManagers    The set of key managers to use to obtain
287       *                        certificates to present to the server if requested.
288       *                        It may be {@code null} or empty if no client
289       *                        certificates will be required or should be provided.
290       * @param  trustManagers  The set of trust managers to use to determine
291       *                        whether to trust server certificates presented to
292       *                        the client.  It may be {@code null} or empty if the
293       *                        default set of trust managers should be used.
294       */
295      public SSLUtil(final KeyManager[] keyManagers,
296                     final TrustManager[] trustManagers)
297      {
298        if ((keyManagers == null) || (keyManagers.length == 0))
299        {
300          this.keyManagers = null;
301        }
302        else
303        {
304          this.keyManagers = keyManagers;
305        }
306    
307        if ((trustManagers == null) || (trustManagers.length == 0))
308        {
309          this.trustManagers = null;
310        }
311        else
312        {
313          this.trustManagers = trustManagers;
314        }
315      }
316    
317    
318    
319      /**
320       * Retrieves the set of key managers configured for use by this class, if any.
321       *
322       * @return  The set of key managers configured for use by this class, or
323       *          {@code null} if none were provided.
324       */
325      public KeyManager[] getKeyManagers()
326      {
327        return keyManagers;
328      }
329    
330    
331    
332      /**
333       * Retrieves the set of trust managers configured for use by this class, if
334       * any.
335       *
336       * @return  The set of trust managers configured for use by this class, or
337       *          {@code null} if none were provided.
338       */
339      public TrustManager[] getTrustManagers()
340      {
341        return trustManagers;
342      }
343    
344    
345    
346      /**
347       * Creates an initialized SSL context created with the configured key and
348       * trust managers.  It will use the protocol returned by the
349       * {@code getDefaultSSLProtocol} method and the JVM-default provider.
350       *
351       * @return  The created SSL context.
352       *
353       * @throws  GeneralSecurityException  If a problem occurs while creating or
354       *                                    initializing the SSL context.
355       */
356      public SSLContext createSSLContext()
357             throws GeneralSecurityException
358      {
359        return createSSLContext(DEFAULT_SSL_PROTOCOL.get());
360      }
361    
362    
363    
364      /**
365       * Creates an initialized SSL context created with the configured key and
366       * trust managers.  It will use the default provider.
367       *
368       * @param  protocol  The protocol to use.  As per the Java SE 6 Cryptography
369       *                   Architecture document, the set of supported protocols
370       *                   should include at least "SSLv3", "TLSv1", "TLSv1.1", and
371       *                   "SSLv2Hello".  It must not be {@code null}.
372       *
373       * @return  The created SSL context.
374       *
375       * @throws  GeneralSecurityException  If a problem occurs while creating or
376       *                                    initializing the SSL context.
377       */
378      public SSLContext createSSLContext(final String protocol)
379             throws GeneralSecurityException
380      {
381        ensureNotNull(protocol);
382    
383        final SSLContext sslContext = SSLContext.getInstance(protocol);
384        sslContext.init(keyManagers, trustManagers, null);
385        return sslContext;
386      }
387    
388    
389    
390      /**
391       * Creates an initialized SSL context created with the configured key and
392       * trust managers.
393       *
394       * @param  protocol  The protocol to use.  As per the Java SE 6 Cryptography
395       *                   Architecture document, the set of supported protocols
396       *                   should include at least "SSLv3", "TLSv1", "TLSv1.1", and
397       *                   "SSLv2Hello".  It must not be {@code null}.
398       * @param  provider  The name of the provider to use for cryptographic
399       *                   operations.  It must not be {@code null}.
400       *
401       * @return  The created SSL context.
402       *
403       * @throws  GeneralSecurityException  If a problem occurs while creating or
404       *                                    initializing the SSL context.
405       */
406      public SSLContext createSSLContext(final String protocol,
407                                         final String provider)
408             throws GeneralSecurityException
409      {
410        ensureNotNull(protocol, provider);
411    
412        final SSLContext sslContext = SSLContext.getInstance(protocol, provider);
413        sslContext.init(keyManagers, trustManagers, null);
414        return sslContext;
415      }
416    
417    
418    
419      /**
420       * Creates an SSL socket factory using the configured key and trust manager
421       * providers.  It will use the protocol returned by the
422       * {@code getDefaultSSLProtocol} method and the JVM-default provider.
423       *
424       * @return  The created SSL socket factory.
425       *
426       * @throws  GeneralSecurityException  If a problem occurs while creating or
427       *                                    initializing the SSL socket factory.
428       */
429      public SSLSocketFactory createSSLSocketFactory()
430             throws GeneralSecurityException
431      {
432        return new SetEnabledProtocolsSSLSocketFactory(
433             createSSLContext().getSocketFactory(),
434             ENABLED_SSL_PROTOCOLS.get());
435      }
436    
437    
438    
439      /**
440       * Creates an SSL socket factory with the configured key and trust managers.
441       * It will use the default provider.
442       *
443       * @param  protocol  The protocol to use.  As per the Java SE 6 Cryptography
444       *                   Architecture document, the set of supported protocols
445       *                   should include at least "SSLv3", "TLSv1", "TLSv1.1", and
446       *                   "SSLv2Hello".  It must not be {@code null}.
447       *
448       * @return  The created SSL socket factory.
449       *
450       * @throws  GeneralSecurityException  If a problem occurs while creating or
451       *                                    initializing the SSL socket factory.
452       */
453      public SSLSocketFactory createSSLSocketFactory(final String protocol)
454             throws GeneralSecurityException
455      {
456        return new SetEnabledProtocolsSSLSocketFactory(
457             createSSLContext(protocol).getSocketFactory(), protocol);
458      }
459    
460    
461    
462      /**
463       * Creates an SSL socket factory with the configured key and trust managers.
464       *
465       * @param  protocol  The protocol to use.  As per the Java SE 6 Cryptography
466       *                   Architecture document, the set of supported protocols
467       *                   should include at least "SSLv3", "TLSv1", "TLSv1.1", and
468       *                   "SSLv2Hello".  It must not be {@code null}.
469       * @param  provider  The name of the provider to use for cryptographic
470       *                   operations.  It must not be {@code null}.
471       *
472       * @return  The created SSL socket factory.
473       *
474       * @throws  GeneralSecurityException  If a problem occurs while creating or
475       *                                    initializing the SSL socket factory.
476       */
477      public SSLSocketFactory createSSLSocketFactory(final String protocol,
478                                                     final String provider)
479             throws GeneralSecurityException
480      {
481        return createSSLContext(protocol, provider).getSocketFactory();
482      }
483    
484    
485    
486      /**
487       * Creates an SSL server socket factory using the configured key and trust
488       * manager providers.  It will use the protocol returned by the
489       * {@code getDefaultSSLProtocol} method and the JVM-default provider.
490       *
491       * @return  The created SSL server socket factory.
492       *
493       * @throws  GeneralSecurityException  If a problem occurs while creating or
494       *                                    initializing the SSL server socket
495       *                                    factory.
496       */
497      public SSLServerSocketFactory createSSLServerSocketFactory()
498             throws GeneralSecurityException
499      {
500        return createSSLContext().getServerSocketFactory();
501      }
502    
503    
504    
505      /**
506       * Creates an SSL server socket factory using the configured key and trust
507       * manager providers.  It will use the JVM-default provider.
508       *
509       * @param  protocol  The protocol to use.  As per the Java SE 6 Cryptography
510       *                   Architecture document, the set of supported protocols
511       *                   should include at least "SSLv3", "TLSv1", "TLSv1.1", and
512       *                   "SSLv2Hello".  It must not be {@code null}.
513       *
514       * @return  The created SSL server socket factory.
515       *
516       * @throws  GeneralSecurityException  If a problem occurs while creating or
517       *                                    initializing the SSL server socket
518       *                                    factory.
519       */
520      public SSLServerSocketFactory createSSLServerSocketFactory(
521                                         final String protocol)
522             throws GeneralSecurityException
523      {
524        return createSSLContext(protocol).getServerSocketFactory();
525      }
526    
527    
528    
529      /**
530       * Creates an SSL server socket factory using the configured key and trust
531       * manager providers.
532       *
533       * @param  protocol  The protocol to use.  As per the Java SE 6 Cryptography
534       *                   Architecture document, the set of supported protocols
535       *                   should include at least "SSLv3", "TLSv1", "TLSv1.1", and
536       *                   "SSLv2Hello".  It must not be {@code null}.
537       * @param  provider  The name of the provider to use for cryptographic
538       *                   operations.  It must not be {@code null}.
539       *
540       * @return  The created SSL server socket factory.
541       *
542       * @throws  GeneralSecurityException  If a problem occurs while creating or
543       *                                    initializing the SSL server socket
544       *                                    factory.
545       */
546      public SSLServerSocketFactory createSSLServerSocketFactory(
547                                         final String protocol,
548                                         final String provider)
549             throws GeneralSecurityException
550      {
551        return createSSLContext(protocol, provider).getServerSocketFactory();
552      }
553    
554    
555    
556      /**
557       * Retrieves the SSL protocol string that will be used by calls to
558       * {@code createSSLContext()} that do not explicitly specify which protocol
559       * to use.
560       *
561       * @return  The SSL protocol string that will be used by calls to create an
562       *          SSL context that do not explicitly specify which protocol to use.
563       */
564      public static String getDefaultSSLProtocol()
565      {
566        return DEFAULT_SSL_PROTOCOL.get();
567      }
568    
569    
570    
571      /**
572       * Specifies the SSL protocol string that will be used by calls to
573       * {@code createSSLContext()} that do not explicitly specify which protocol
574       * to use.
575       *
576       * @param  defaultSSLProtocol  The SSL protocol string that will be used by
577       *                             calls to create an SSL context that do not
578       *                             explicitly specify which protocol to use.  It
579       *                             must not be {@code null}.
580       */
581      public static void setDefaultSSLProtocol(final String defaultSSLProtocol)
582      {
583        ensureNotNull(defaultSSLProtocol);
584    
585        DEFAULT_SSL_PROTOCOL.set(defaultSSLProtocol);
586      }
587    
588    
589    
590      /**
591       * Retrieves the set of SSL protocols that will be enabled for use, if
592       * available, for SSL sockets created within the LDAP SDK.
593       *
594       * @return  The set of SSL protocols that will be enabled for use, if
595       *          available, for SSL sockets created within the LDAP SDK.
596       */
597      public static Set<String> getEnabledSSLProtocols()
598      {
599        return ENABLED_SSL_PROTOCOLS.get();
600      }
601    
602    
603    
604      /**
605       * Specifies the set of SSL protocols that will be enabled for use for SSL
606       * sockets created within the LDAP SDK.  When creating an SSL socket, the
607       * {@code SSLSocket.getSupportedProtocols} method will be used to determine
608       * which protocols are supported for that socket, and then the
609       * {@code SSLSocket.setEnabledProtocols} method will be used to enable those
610       * protocols which are listed as both supported by the socket and included in
611       * this set.  If the provided set is {@code null} or empty, then the default
612       * set of enabled protocols will be used.
613       *
614       * @param  enabledSSLProtocols  The set of SSL protocols that will be enabled
615       *                              for use for SSL sockets created within the
616       *                              LDAP SDK.  It may be {@code null} or empty to
617       *                              indicate that the JDK-default set of enabled
618       *                              protocols should be used for the socket.
619       */
620      public static void setEnabledSSLProtocols(
621                              final Collection<String> enabledSSLProtocols)
622      {
623        if (enabledSSLProtocols == null)
624        {
625          ENABLED_SSL_PROTOCOLS.set(Collections.<String>emptySet());
626        }
627        else
628        {
629          ENABLED_SSL_PROTOCOLS.set(Collections.unmodifiableSet(
630               new HashSet<String>(enabledSSLProtocols)));
631        }
632      }
633    
634    
635    
636      /**
637       * Updates the provided socket to apply the appropriate set of enabled SSL
638       * protocols.  This will only have any effect for sockets that are instances
639       * of {@code javax.net.ssl.SSLSocket}, but it is safe to call for any kind of
640       * {@code java.net.Socket}.  This should be called before attempting any
641       * communication over the socket, as
642       *
643       * @param  socket  The socket on which to apply the configured set of enabled
644       *                 SSL protocols.
645       *
646       * @throws  LDAPException  If {@code getEnabledSSLProtocols} returns a
647       *                         non-empty set but none of the values in that set
648       *                         are supported by the socket.
649       */
650      public static void applyEnabledSSLProtocols(final Socket socket)
651             throws LDAPException
652      {
653        try
654        {
655          applyEnabledSSLProtocols(socket, ENABLED_SSL_PROTOCOLS.get());
656        }
657        catch (final IOException ioe)
658        {
659          Debug.debugException(ioe);
660          throw new LDAPException(ResultCode.CONNECT_ERROR, ioe.getMessage(), ioe);
661        }
662      }
663    
664    
665    
666      /**
667       * Updates the provided socket to apply the appropriate set of enabled SSL
668       * protocols.  This will only have any effect for sockets that are instances
669       * of {@code javax.net.ssl.SSLSocket}, but it is safe to call for any kind of
670       * {@code java.net.Socket}.  This should be called before attempting any
671       * communication over the socket, as
672       *
673       * @param  socket     The socket on which to apply the configured set of
674       *                    enabled SSL protocols.
675       * @param  protocols  The set of protocols that should be enabled for the
676       *                    socket, if available.
677       *
678       * @throws  IOException  If {@code getEnabledSSLProtocols} returns a
679       *                       non-empty set but none of the values in that set are
680       *                       supported by the socket.
681       */
682      static void applyEnabledSSLProtocols(final Socket socket,
683                                           final Set<String> protocols)
684             throws IOException
685      {
686        if ((socket == null) || (!(socket instanceof SSLSocket)) ||
687            protocols.isEmpty())
688        {
689          return;
690        }
691    
692        final Set<String> lowerProtocols = new HashSet<String>(protocols.size());
693        for (final String s : protocols)
694        {
695          lowerProtocols.add(StaticUtils.toLowerCase(s));
696        }
697    
698        final SSLSocket sslSocket = (SSLSocket) socket;
699        final String[] supportedProtocols = sslSocket.getSupportedProtocols();
700    
701        final ArrayList<String> enabledList =
702             new ArrayList<String>(supportedProtocols.length);
703        for (final String supportedProtocol : supportedProtocols)
704        {
705          if (lowerProtocols.contains(StaticUtils.toLowerCase(supportedProtocol)))
706          {
707            enabledList.add(supportedProtocol);
708          }
709        }
710    
711        if (enabledList.isEmpty())
712        {
713          final StringBuilder enabledBuffer = new StringBuilder();
714          final Iterator<String> enabledIterator = protocols.iterator();
715          while (enabledIterator.hasNext())
716          {
717            enabledBuffer.append('\'');
718            enabledBuffer.append(enabledIterator.next());
719            enabledBuffer.append('\'');
720    
721            if (enabledIterator.hasNext())
722            {
723              enabledBuffer.append(", ");
724            }
725          }
726    
727          final StringBuilder supportedBuffer = new StringBuilder();
728          for (int i=0; i < supportedProtocols.length; i++)
729          {
730            if (i > 0)
731            {
732              supportedBuffer.append(", ");
733            }
734    
735            supportedBuffer.append('\'');
736            supportedBuffer.append(supportedProtocols[i]);
737            supportedBuffer.append('\'');
738          }
739    
740          throw new IOException(
741               ERR_NO_ENABLED_SSL_PROTOCOLS_AVAILABLE_FOR_SOCKET.get(
742                    enabledBuffer.toString(), supportedBuffer.toString(),
743                    PROPERTY_ENABLED_SSL_PROTOCOLS,
744                    SSLUtil.class.getName() + ".setEnabledSSLProtocols"));
745        }
746        else
747        {
748          final String[] enabledArray = new String[enabledList.size()];
749          sslSocket.setEnabledProtocols(enabledList.toArray(enabledArray));
750        }
751      }
752    
753    
754    
755      /**
756       * Configures SSL default settings for the LDAP SDK.  This method is
757       * non-private for purposes of easier test coverage.
758       */
759      static void configureSSLDefaults()
760      {
761        // See if there is a system property that specifies what the default SSL
762        // protocol should be.  If not, then try to dynamically determine it.
763        final String defaultPropValue =
764             System.getProperty(PROPERTY_DEFAULT_SSL_PROTOCOL);
765        if ((defaultPropValue != null) && (defaultPropValue.length() > 0))
766        {
767          DEFAULT_SSL_PROTOCOL.set(defaultPropValue);
768        }
769        else
770        {
771          // Ideally, we should be able to discover the SSL protocol that offers the
772          // best mix of security and compatibility.  Unfortunately, Java SE 5
773          // doesn't expose the methods necessary to allow us to do that, but if the
774          // running JVM is Java SE 6 or later, then we can use reflection to invoke
775          // those methods and make the appropriate determination.  If we see that
776          // TLSv1.1 and/or TLSv1.2 are available, then we'll add those to the set
777          // of default enabled protocols.
778          try
779          {
780            final Method getDefaultMethod =
781                 SSLContext.class.getMethod("getDefault");
782            final SSLContext defaultContext =
783                 (SSLContext) getDefaultMethod.invoke(null);
784    
785            final Method getSupportedParamsMethod =
786                 SSLContext.class.getMethod("getSupportedSSLParameters");
787            final Object paramsObj =
788                 getSupportedParamsMethod.invoke(defaultContext);
789    
790            final Class<?> sslParamsClass =
791                 Class.forName("javax.net.ssl.SSLParameters");
792            final Method getProtocolsMethod =
793                 sslParamsClass.getMethod("getProtocols");
794            final String[] supportedProtocols =
795                 (String[]) getProtocolsMethod.invoke(paramsObj);
796    
797            final HashSet<String> protocolMap =
798                 new HashSet<String>(Arrays.asList(supportedProtocols));
799            if (protocolMap.contains("TLSv1.2"))
800            {
801              DEFAULT_SSL_PROTOCOL.set("TLSv1.2");
802            }
803            else if (protocolMap.contains("TLSv1.1"))
804            {
805              DEFAULT_SSL_PROTOCOL.set("TLSv1.1");
806            }
807            else if (protocolMap.contains("TLSv1"))
808            {
809              DEFAULT_SSL_PROTOCOL.set("TLSv1");
810            }
811          }
812          catch (final Exception e)
813          {
814            Debug.debugException(e);
815          }
816        }
817    
818        // A set to use for the default set of enabled protocols.  Unless otherwise
819        // specified via system property, we'll always enable TLSv1.  We may enable
820        // other protocols based on the default protocol.  The default set of
821        // enabled protocols will not include SSLv3 even if the JVM might otherwise
822        // include it as a default enabled protocol because of known security
823        // problems with SSLv3.
824        final HashSet<String> enabledProtocols = new HashSet<String>(10);
825        enabledProtocols.add("TLSv1");
826        if (DEFAULT_SSL_PROTOCOL.get().equals("TLSv1.2"))
827        {
828          enabledProtocols.add("TLSv1.1");
829          enabledProtocols.add("TLSv1.2");
830        }
831        else if (DEFAULT_SSL_PROTOCOL.get().equals("TLSv1.1"))
832        {
833          enabledProtocols.add("TLSv1.1");
834        }
835    
836        // If there is a system property that specifies which enabled SSL protocols
837        // to use, then it will override the defaults.
838        final String enabledPropValue =
839             System.getProperty(PROPERTY_ENABLED_SSL_PROTOCOLS);
840        if ((enabledPropValue != null) && (enabledPropValue.length() > 0))
841        {
842          enabledProtocols.clear();
843    
844          final StringTokenizer tokenizer = new StringTokenizer(enabledPropValue,
845               ", ", false);
846          while (tokenizer.hasMoreTokens())
847          {
848            final String token = tokenizer.nextToken();
849            if (token.length() > 0)
850            {
851              enabledProtocols.add(token);
852            }
853          }
854        }
855    
856        ENABLED_SSL_PROTOCOLS.set(Collections.unmodifiableSet(enabledProtocols));
857      }
858    }