001/*
002 * Copyright 2008-2017 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2017 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 */
021package com.unboundid.util.ssl;
022
023
024
025import java.io.IOException;
026import java.lang.reflect.Method;
027import java.net.ServerSocket;
028import java.net.Socket;
029import java.security.GeneralSecurityException;
030import java.security.cert.X509Certificate;
031import java.util.ArrayList;
032import java.util.Arrays;
033import java.util.Collection;
034import java.util.Collections;
035import java.util.HashSet;
036import java.util.Iterator;
037import java.util.Set;
038import java.util.StringTokenizer;
039import java.util.concurrent.atomic.AtomicReference;
040import javax.net.ssl.KeyManager;
041import javax.net.ssl.SSLContext;
042import javax.net.ssl.SSLServerSocket;
043import javax.net.ssl.SSLSocket;
044import javax.net.ssl.SSLSocketFactory;
045import javax.net.ssl.SSLServerSocketFactory;
046import javax.net.ssl.TrustManager;
047import javax.security.auth.x500.X500Principal;
048
049import com.unboundid.ldap.sdk.LDAPException;
050import com.unboundid.ldap.sdk.ResultCode;
051import com.unboundid.util.Debug;
052import com.unboundid.util.StaticUtils;
053import com.unboundid.util.ThreadSafety;
054import com.unboundid.util.ThreadSafetyLevel;
055
056import static com.unboundid.util.Validator.*;
057import 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)
123public 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}