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