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