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