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