001/*
002 * Copyright 2008-2020 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright 2008-2020 Ping Identity Corporation
007 *
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *    http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 */
020/*
021 * Copyright (C) 2008-2020 Ping Identity Corporation
022 *
023 * This program is free software; you can redistribute it and/or modify
024 * it under the terms of the GNU General Public License (GPLv2 only)
025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
026 * as published by the Free Software Foundation.
027 *
028 * This program is distributed in the hope that it will be useful,
029 * but WITHOUT ANY WARRANTY; without even the implied warranty of
030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
031 * GNU General Public License for more details.
032 *
033 * You should have received a copy of the GNU General Public License
034 * along with this program; if not, see <http://www.gnu.org/licenses>.
035 */
036package com.unboundid.util.ssl;
037
038
039
040import java.io.IOException;
041import java.net.ServerSocket;
042import java.net.Socket;
043import java.security.GeneralSecurityException;
044import java.security.cert.X509Certificate;
045import java.util.ArrayList;
046import java.util.Arrays;
047import java.util.Collection;
048import java.util.Collections;
049import java.util.Iterator;
050import java.util.LinkedHashSet;
051import java.util.Set;
052import java.util.StringTokenizer;
053import java.util.concurrent.atomic.AtomicReference;
054import javax.net.ssl.KeyManager;
055import javax.net.ssl.SSLContext;
056import javax.net.ssl.SSLServerSocket;
057import javax.net.ssl.SSLSocket;
058import javax.net.ssl.SSLSocketFactory;
059import javax.net.ssl.SSLServerSocketFactory;
060import javax.net.ssl.TrustManager;
061import javax.security.auth.x500.X500Principal;
062
063import com.unboundid.ldap.sdk.LDAPException;
064import com.unboundid.ldap.sdk.ResultCode;
065import com.unboundid.util.Debug;
066import com.unboundid.util.NotNull;
067import com.unboundid.util.Nullable;
068import com.unboundid.util.StaticUtils;
069import com.unboundid.util.ThreadSafety;
070import com.unboundid.util.ThreadSafetyLevel;
071import com.unboundid.util.Validator;
072
073import static com.unboundid.util.ssl.SSLMessages.*;
074
075
076
077/**
078 * This class provides a simple interface for creating {@code SSLContext} and
079 * {@code SSLSocketFactory} instances, which may be used to create SSL-based
080 * connections, or secure existing connections with StartTLS.  Support for the
081 * TLSv1, TLSv1.1, TLSv1.2, and TLSv1.3 protocols will be enabled by default (if
082 * the JVM supports them), with TLSv1.3 being the preferred protocol.
083 * <BR><BR>
084 * <H2>Example 1</H2>
085 * The following example demonstrates the use of the SSL helper to create an
086 * SSL-based LDAP connection that will blindly trust any certificate that the
087 * server presents.  Using the {@code TrustAllTrustManager} is only recommended
088 * for testing purposes, since blindly trusting any certificate is not secure.
089 * <PRE>
090 * // Create an SSLUtil instance that is configured to trust any certificate,
091 * // and use it to create a socket factory.
092 * SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager());
093 * SSLSocketFactory sslSocketFactory = sslUtil.createSSLSocketFactory();
094 *
095 * // Establish a secure connection using the socket factory.
096 * LDAPConnection connection = new LDAPConnection(sslSocketFactory);
097 * connection.connect(serverAddress, serverSSLPort);
098 *
099 * // Process operations using the connection....
100 * RootDSE rootDSE = connection.getRootDSE();
101 *
102 * connection.close();
103 * </PRE>
104 * <BR>
105 * <H2>Example 2</H2>
106 * The following example demonstrates the use of the SSL helper to create a
107 * non-secure LDAP connection and then use the StartTLS extended operation to
108 * secure it.  It will use a trust store to determine whether to trust the
109 * server certificate.
110 * <PRE>
111 * // Establish a non-secure connection to the server.
112 * LDAPConnection connection = new LDAPConnection(serverAddress, serverPort);
113 *
114 * // Create an SSLUtil instance that is configured to trust certificates in
115 * // a specified trust store file, and use it to create an SSLContext that
116 * // will be used for StartTLS processing.
117 * SSLUtil sslUtil = new SSLUtil(new TrustStoreTrustManager(trustStorePath));
118 * SSLContext sslContext = sslUtil.createSSLContext();
119 *
120 * // Use the StartTLS extended operation to secure the connection.
121 * StartTLSExtendedRequest startTLSRequest =
122 *      new StartTLSExtendedRequest(sslContext);
123 * ExtendedResult startTLSResult;
124 * try
125 * {
126 *   startTLSResult = connection.processExtendedOperation(startTLSRequest);
127 * }
128 * catch (LDAPException le)
129 * {
130 *   startTLSResult = new ExtendedResult(le);
131 * }
132 * LDAPTestUtils.assertResultCodeEquals(startTLSResult, ResultCode.SUCCESS);
133 *
134 * // Process operations using the connection....
135 * RootDSE rootDSE = connection.getRootDSE();
136 *
137 * connection.close();
138 * </PRE>
139 */
140@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
141public final class SSLUtil
142{
143  /**
144   * The name of the system property that can be used to specify the initial
145   * value for the default SSL protocol that should be used.  If this is not
146   * set, then the default SSL protocol will be dynamically determined.  This
147   * can be overridden via the {@link #setDefaultSSLProtocol(String)} method.
148   */
149  @NotNull public static final String PROPERTY_DEFAULT_SSL_PROTOCOL =
150       "com.unboundid.util.SSLUtil.defaultSSLProtocol";
151
152
153
154  /**
155   * The name of the system property that can be used to provide the initial
156   * set of enabled SSL protocols that should be used, as a comma-delimited
157   * list.  If this is not set, then the enabled SSL protocols will be
158   * dynamically determined.  This can be overridden via the
159   * {@link #setEnabledSSLProtocols(Collection)} method.
160   */
161  @NotNull public static final String PROPERTY_ENABLED_SSL_PROTOCOLS =
162       "com.unboundid.util.SSLUtil.enabledSSLProtocols";
163
164
165
166  /**
167   * The name of the system property that can be used to provide the initial
168   * set of enabled SSL cipher suites that should be used, as a comma-delimited
169   * list.  If this is not set, then the enabled SSL cipher suites will be
170   * dynamically determined.  This can be overridden via the
171   * {@link #setEnabledSSLCipherSuites(Collection)} method.
172   */
173  @NotNull public static final String PROPERTY_ENABLED_SSL_CIPHER_SUITES =
174       "com.unboundid.util.SSLUtil.enabledSSLCipherSuites";
175
176
177
178  /**
179   * The name of the SSL protocol that can be used to request TLSv1.3.
180   */
181  @NotNull public static final String SSL_PROTOCOL_TLS_1_3 = "TLSv1.3";
182
183
184
185  /**
186   * The name of the SSL protocol that can be used to request TLSv1.2.
187   */
188  @NotNull public static final String SSL_PROTOCOL_TLS_1_2 = "TLSv1.2";
189
190
191
192  /**
193   * The name of the SSL protocol that can be used to request TLSv1.1.
194   */
195  @NotNull public static final String SSL_PROTOCOL_TLS_1_1 = "TLSv1.1";
196
197
198
199  /**
200   * The name of the SSL protocol that can be used to request TLSv1.
201   */
202  @NotNull public static final String SSL_PROTOCOL_TLS_1 = "TLSv1";
203
204
205
206  /**
207   * The name of the SSL protocol that can be used to request SSLv3.
208   */
209  @NotNull public static final String SSL_PROTOCOL_SSL_3 = "SSLv3";
210
211
212
213  /**
214   * The name of the SSL protocol that can be used to request SSLv2Hello.
215   */
216  @NotNull public static final String SSL_PROTOCOL_SSL_2_HELLO = "SSLv2Hello";
217
218
219
220  /**
221   * The default protocol string that will be used to create SSL contexts when
222   * no explicit protocol is specified.
223   */
224  @NotNull private static final AtomicReference<String> DEFAULT_SSL_PROTOCOL =
225       new AtomicReference<>(SSL_PROTOCOL_TLS_1);
226
227
228
229  /**
230   * The default set of SSL cipher suites that will be enabled for use if
231   * available for SSL sockets created within the LDAP SDK.
232   */
233  @NotNull private static final AtomicReference<Set<String>>
234       ENABLED_SSL_CIPHER_SUITES = new AtomicReference<>();
235
236
237
238  /**
239   * The default set of SSL protocols that will be enabled for use if available
240   * for SSL sockets created within the LDAP SDK.
241   */
242  @NotNull private static final AtomicReference<Set<String>>
243       ENABLED_SSL_PROTOCOLS = new AtomicReference<>();
244
245
246
247  static
248  {
249    configureSSLDefaults();
250  }
251
252
253
254  // The set of key managers to be used.
255  @Nullable private final KeyManager[] keyManagers;
256
257  // The set of trust managers to be used.
258  @Nullable private final TrustManager[] trustManagers;
259
260
261
262  /**
263   * Creates a new SSLUtil instance that will not have a custom key manager or
264   * trust manager.  It will not be able to provide a certificate to the server
265   * if one is requested, and it will only trust certificates signed by a
266   * predefined set of authorities.
267   */
268  public SSLUtil()
269  {
270    keyManagers   = null;
271    trustManagers = null;
272  }
273
274
275
276  /**
277   * Creates a new SSLUtil instance that will use the provided trust manager to
278   * determine whether to trust server certificates presented to the client.
279   * It will not be able to provide a certificate to the server if one is
280   * requested.
281   *
282   * @param  trustManager  The trust manager to use to determine whether to
283   *                       trust server certificates presented to the client.
284   *                       It may be {@code null} if the default set of trust
285   *                       managers should be used.
286   */
287  public SSLUtil(@Nullable final TrustManager trustManager)
288  {
289    keyManagers = null;
290
291    if (trustManager == null)
292    {
293      trustManagers = null;
294    }
295    else
296    {
297      trustManagers = new TrustManager[] { trustManager };
298    }
299  }
300
301
302
303  /**
304   * Creates a new SSLUtil instance that will use the provided trust managers
305   * to determine whether to trust server certificates presented to the client.
306   * It will not be able to provide a certificate to the server if one is
307   * requested.
308   *
309   * @param  trustManagers  The set of trust managers to use to determine
310   *                        whether to trust server certificates presented to
311   *                        the client.  It may be {@code null} or empty if the
312   *                        default set of trust managers should be used.
313   */
314  public SSLUtil(@Nullable final TrustManager[] trustManagers)
315  {
316    keyManagers = null;
317
318    if ((trustManagers == null) || (trustManagers.length == 0))
319    {
320      this.trustManagers = null;
321    }
322    else
323    {
324      this.trustManagers = trustManagers;
325    }
326  }
327
328
329
330  /**
331   * Creates a new SSLUtil instance that will use the provided key manager to
332   * obtain certificates to present to the server, and the provided trust
333   * manager to determine whether to trust server certificates presented to the
334   * client.
335   *
336   * @param  keyManager    The key manager to use to obtain certificates to
337   *                       present to the server if requested.  It may be
338   *                       {@code null} if no client certificates will be
339   *                       required or should be provided.
340   * @param  trustManager  The trust manager to use to determine whether to
341   *                       trust server certificates presented to the client.
342   *                       It may be {@code null} if the default set of trust
343   *                       managers should be used.
344   */
345  public SSLUtil(@Nullable final KeyManager keyManager,
346                 @Nullable final TrustManager trustManager)
347  {
348    if (keyManager == null)
349    {
350      keyManagers = null;
351    }
352    else
353    {
354      keyManagers = new KeyManager[] { keyManager };
355    }
356
357    if (trustManager == null)
358    {
359      trustManagers = null;
360    }
361    else
362    {
363      trustManagers = new TrustManager[] { trustManager };
364    }
365  }
366
367
368
369  /**
370   * Creates a new SSLUtil instance that will use the provided key managers to
371   * obtain certificates to present to the server, and the provided trust
372   * managers to determine whether to trust server certificates presented to the
373   * client.
374   *
375   * @param  keyManagers    The set of key managers to use to obtain
376   *                        certificates to present to the server if requested.
377   *                        It may be {@code null} or empty if no client
378   *                        certificates will be required or should be provided.
379   * @param  trustManagers  The set of trust managers to use to determine
380   *                        whether to trust server certificates presented to
381   *                        the client.  It may be {@code null} or empty if the
382   *                        default set of trust managers should be used.
383   */
384  public SSLUtil(@Nullable final KeyManager[] keyManagers,
385                 @Nullable final TrustManager[] trustManagers)
386  {
387    if ((keyManagers == null) || (keyManagers.length == 0))
388    {
389      this.keyManagers = null;
390    }
391    else
392    {
393      this.keyManagers = keyManagers;
394    }
395
396    if ((trustManagers == null) || (trustManagers.length == 0))
397    {
398      this.trustManagers = null;
399    }
400    else
401    {
402      this.trustManagers = trustManagers;
403    }
404  }
405
406
407
408  /**
409   * Retrieves the set of key managers configured for use by this class, if any.
410   *
411   * @return  The set of key managers configured for use by this class, or
412   *          {@code null} if none were provided.
413   */
414  @Nullable()
415  public KeyManager[] getKeyManagers()
416  {
417    return keyManagers;
418  }
419
420
421
422  /**
423   * Retrieves the set of trust managers configured for use by this class, if
424   * any.
425   *
426   * @return  The set of trust managers configured for use by this class, or
427   *          {@code null} if none were provided.
428   */
429  @Nullable()
430  public TrustManager[] getTrustManagers()
431  {
432    return trustManagers;
433  }
434
435
436
437  /**
438   * Creates an initialized SSL context created with the configured key and
439   * trust managers.  It will use the protocol returned by the
440   * {@link #getDefaultSSLProtocol} method and the JVM-default provider.
441   *
442   * @return  The created SSL context.
443   *
444   * @throws  GeneralSecurityException  If a problem occurs while creating or
445   *                                    initializing the SSL context.
446   */
447  @NotNull()
448  public SSLContext createSSLContext()
449         throws GeneralSecurityException
450  {
451    return createSSLContext(DEFAULT_SSL_PROTOCOL.get());
452  }
453
454
455
456  /**
457   * Creates an initialized SSL context created with the configured key and
458   * trust managers.  It will use the default provider.
459   *
460   * @param  protocol  The SSL protocol to use.  The Java Secure Socket
461   *                   Extension (JSSE) Reference Guide provides a list of the
462   *                   supported protocols, but commonly used values are
463   *                   "TLSv1.3", "TLSv1.2", "TLSv1.1", and "TLSv1".  This must
464   *                   not be {@code null}.
465   *
466   *
467   * @return  The created SSL context.
468   *
469   * @throws  GeneralSecurityException  If a problem occurs while creating or
470   *                                    initializing the SSL context.
471   */
472  @NotNull()
473  public SSLContext createSSLContext(@NotNull final String protocol)
474         throws GeneralSecurityException
475  {
476    Validator.ensureNotNull(protocol);
477
478    final SSLContext sslContext = SSLContext.getInstance(protocol);
479    sslContext.init(keyManagers, trustManagers, null);
480    return sslContext;
481  }
482
483
484
485  /**
486   * Creates an initialized SSL context created with the configured key and
487   * trust managers.
488   *
489   * @param  protocol  The SSL protocol to use.  The Java Secure Socket
490   *                   Extension (JSSE) Reference Guide provides a list of the
491   *                   supported protocols, but commonly used values are
492   *                   "TLSv1.3", "TLSv1.2", "TLSv1.1", and "TLSv1".  This must
493   *                   not be {@code null}.
494   * @param  provider  The name of the provider to use for cryptographic
495   *                   operations.  It must not be {@code null}.
496   *
497   * @return  The created SSL context.
498   *
499   * @throws  GeneralSecurityException  If a problem occurs while creating or
500   *                                    initializing the SSL context.
501   */
502  @NotNull()
503  public SSLContext createSSLContext(@NotNull final String protocol,
504                                     @NotNull final String provider)
505         throws GeneralSecurityException
506  {
507    Validator.ensureNotNull(protocol, provider);
508
509    final SSLContext sslContext = SSLContext.getInstance(protocol, provider);
510    sslContext.init(keyManagers, trustManagers, null);
511    return sslContext;
512  }
513
514
515
516  /**
517   * Creates an SSL socket factory using the configured key and trust manager
518   * providers.  It will use the protocol returned by the
519   * {@link #getDefaultSSLProtocol} method and the JVM-default provider.
520   *
521   * @return  The created SSL socket factory.
522   *
523   * @throws  GeneralSecurityException  If a problem occurs while creating or
524   *                                    initializing the SSL socket factory.
525   */
526  @NotNull()
527  public SSLSocketFactory createSSLSocketFactory()
528         throws GeneralSecurityException
529  {
530    return new SetEnabledProtocolsAndCipherSuitesSSLSocketFactory(
531         createSSLContext().getSocketFactory(),
532         ENABLED_SSL_PROTOCOLS.get(), ENABLED_SSL_CIPHER_SUITES.get());
533  }
534
535
536
537  /**
538   * Creates an SSL socket factory with the configured key and trust managers.
539   * It will use the default provider.
540   *
541   * @param  protocol  The SSL protocol to use.  The Java Secure Socket
542   *                   Extension (JSSE) Reference Guide provides a list of the
543   *                   supported protocols, but commonly used values are
544   *                   "TLSv1.3", "TLSv1.2", "TLSv1.1", and "TLSv1".  This must
545   *                   not be {@code null}.
546   *
547   * @return  The created SSL socket factory.
548   *
549   * @throws  GeneralSecurityException  If a problem occurs while creating or
550   *                                    initializing the SSL socket factory.
551   */
552  @NotNull()
553  public SSLSocketFactory createSSLSocketFactory(
554                               @NotNull final String protocol)
555         throws GeneralSecurityException
556  {
557    return new SetEnabledProtocolsAndCipherSuitesSSLSocketFactory(
558         createSSLContext(protocol).getSocketFactory(), protocol,
559         ENABLED_SSL_CIPHER_SUITES.get());
560  }
561
562
563
564  /**
565   * Creates an SSL socket factory with the configured key and trust managers.
566   *
567   * @param  protocol  The SSL protocol to use.  The Java Secure Socket
568   *                   Extension (JSSE) Reference Guide provides a list of the
569   *                   supported protocols, but commonly used values are
570   *                   "TLSv1.3", "TLSv1.2", "TLSv1.1", and "TLSv1".  This must
571   *                   not be {@code null}.
572   * @param  provider  The name of the provider to use for cryptographic
573   *                   operations.  It must not be {@code null}.
574   *
575   * @return  The created SSL socket factory.
576   *
577   * @throws  GeneralSecurityException  If a problem occurs while creating or
578   *                                    initializing the SSL socket factory.
579   */
580  @NotNull()
581  public SSLSocketFactory createSSLSocketFactory(@NotNull final String protocol,
582                                                 @NotNull final String provider)
583         throws GeneralSecurityException
584  {
585    return createSSLContext(protocol, provider).getSocketFactory();
586  }
587
588
589
590  /**
591   * Creates an SSL server socket factory using the configured key and trust
592   * manager providers.  It will use the protocol returned by the
593   * {@link #getDefaultSSLProtocol} method and the JVM-default provider.
594   *
595   * @return  The created SSL server socket factory.
596   *
597   * @throws  GeneralSecurityException  If a problem occurs while creating or
598   *                                    initializing the SSL server socket
599   *                                    factory.
600   */
601  @NotNull()
602  public SSLServerSocketFactory createSSLServerSocketFactory()
603         throws GeneralSecurityException
604  {
605    return new SetEnabledProtocolsAndCipherSuitesSSLServerSocketFactory(
606         createSSLContext().getServerSocketFactory(),
607         ENABLED_SSL_PROTOCOLS.get(), ENABLED_SSL_CIPHER_SUITES.get());
608  }
609
610
611
612  /**
613   * Creates an SSL server socket factory using the configured key and trust
614   * manager providers.  It will use the JVM-default provider.
615   *
616   * @param  protocol  The SSL protocol to use.  The Java Secure Socket
617   *                   Extension (JSSE) Reference Guide provides a list of the
618   *                   supported protocols, but commonly used values are
619   *                   "TLSv1.3", "TLSv1.2", "TLSv1.1", and "TLSv1".  This must
620   *                   not be {@code null}.
621   *
622   * @return  The created SSL server socket factory.
623   *
624   * @throws  GeneralSecurityException  If a problem occurs while creating or
625   *                                    initializing the SSL server socket
626   *                                    factory.
627   */
628  @NotNull()
629  public SSLServerSocketFactory createSSLServerSocketFactory(
630                                     @NotNull final String protocol)
631         throws GeneralSecurityException
632  {
633    return new SetEnabledProtocolsAndCipherSuitesSSLServerSocketFactory(
634         createSSLContext(protocol).getServerSocketFactory(), protocol,
635         ENABLED_SSL_CIPHER_SUITES.get());
636  }
637
638
639
640  /**
641   * Creates an SSL server socket factory using the configured key and trust
642   * manager providers.
643   *
644   * @param  protocol  The SSL protocol to use.  The Java Secure Socket
645   *                   Extension (JSSE) Reference Guide provides a list of the
646   *                   supported protocols, but commonly used values are
647   *                   "TLSv1.3", "TLSv1.2", "TLSv1.1", and "TLSv1".  This must
648   *                   not be {@code null}.
649   * @param  provider  The name of the provider to use for cryptographic
650   *                   operations.  It must not be {@code null}.
651   *
652   * @return  The created SSL server socket factory.
653   *
654   * @throws  GeneralSecurityException  If a problem occurs while creating or
655   *                                    initializing the SSL server socket
656   *                                    factory.
657   */
658  @NotNull()
659  public SSLServerSocketFactory createSSLServerSocketFactory(
660                                     @NotNull final String protocol,
661                                     @NotNull final String provider)
662         throws GeneralSecurityException
663  {
664    return createSSLContext(protocol, provider).getServerSocketFactory();
665  }
666
667
668
669  /**
670   * Retrieves the SSL protocol string that will be used by calls to
671   * {@link #createSSLContext()} that do not explicitly specify which protocol
672   * to use.
673   *
674   * @return  The SSL protocol string that will be used by calls to create an
675   *          SSL context that do not explicitly specify which protocol to use.
676   */
677  @NotNull()
678  public static String getDefaultSSLProtocol()
679  {
680    return DEFAULT_SSL_PROTOCOL.get();
681  }
682
683
684
685  /**
686   * Specifies the SSL protocol string that will be used by calls to
687   * {@link #createSSLContext()} that do not explicitly specify which protocol
688   * to use.
689   *
690   * @param  defaultSSLProtocol  The SSL protocol string that will be used by
691   *                             calls to create an SSL context that do not
692   *                             explicitly specify which protocol to use.  It
693   *                             must not be {@code null}.
694   */
695  public static void setDefaultSSLProtocol(
696                          @NotNull final String defaultSSLProtocol)
697  {
698    Validator.ensureNotNull(defaultSSLProtocol);
699
700    DEFAULT_SSL_PROTOCOL.set(defaultSSLProtocol);
701  }
702
703
704
705  /**
706   * Retrieves the set of SSL protocols that will be enabled for use, if
707   * available, for SSL sockets created within the LDAP SDK.
708   *
709   * @return  The set of SSL protocols that will be enabled for use, if
710   *          available, for SSL sockets created within the LDAP SDK.
711   */
712  @NotNull()
713  public static Set<String> getEnabledSSLProtocols()
714  {
715    return ENABLED_SSL_PROTOCOLS.get();
716  }
717
718
719
720  /**
721   * Specifies the set of SSL protocols that will be enabled for use for SSL
722   * sockets created within the LDAP SDK.  When creating an SSL socket, the
723   * {@code SSLSocket.getSupportedProtocols} method will be used to determine
724   * which protocols are supported for that socket, and then the
725   * {@code SSLSocket.setEnabledProtocols} method will be used to enable those
726   * protocols which are listed as both supported by the socket and included in
727   * this set.  If the provided set is {@code null} or empty, then the default
728   * set of enabled protocols will be used.
729   *
730   * @param  enabledSSLProtocols  The set of SSL protocols that will be enabled
731   *                              for use for SSL sockets created within the
732   *                              LDAP SDK.  It may be {@code null} or empty to
733   *                              indicate that the JDK-default set of enabled
734   *                              protocols should be used for the socket.
735   */
736  public static void setEnabledSSLProtocols(
737              @Nullable final Collection<String> enabledSSLProtocols)
738  {
739    if (enabledSSLProtocols == null)
740    {
741      ENABLED_SSL_PROTOCOLS.set(Collections.<String>emptySet());
742    }
743    else
744    {
745      ENABLED_SSL_PROTOCOLS.set(Collections.unmodifiableSet(
746           new LinkedHashSet<>(enabledSSLProtocols)));
747    }
748  }
749
750
751
752  /**
753   * Updates the provided socket to apply the appropriate set of enabled SSL
754   * protocols.  This will only have any effect for sockets that are instances
755   * of {@code javax.net.ssl.SSLSocket}, but it is safe to call for any kind of
756   * {@code java.net.Socket}.  This should be called before attempting any
757   * communication over the socket.
758   *
759   * @param  socket  The socket on which to apply the configured set of enabled
760   *                 SSL protocols.
761   *
762   * @throws  LDAPException  If {@link #getEnabledSSLProtocols} returns a
763   *                         non-empty set but none of the values in that set
764   *                         are supported by the socket.
765   */
766  public static void applyEnabledSSLProtocols(@NotNull final Socket socket)
767       throws LDAPException
768  {
769    try
770    {
771      applyEnabledSSLProtocols(socket, ENABLED_SSL_PROTOCOLS.get());
772    }
773    catch (final IOException ioe)
774    {
775      Debug.debugException(ioe);
776      throw new LDAPException(ResultCode.CONNECT_ERROR, ioe.getMessage(), ioe);
777    }
778  }
779
780
781
782  /**
783   * Updates the provided socket to apply the appropriate set of enabled SSL
784   * protocols.  This will only have any effect for sockets that are instances
785   * of {@code javax.net.ssl.SSLSocket}, but it is safe to call for any kind of
786   * {@code java.net.Socket}.  This should be called before attempting any
787   * communication over the socket.
788   *
789   * @param  socket     The socket on which to apply the configured set of
790   *                    enabled SSL protocols.
791   * @param  protocols  The set of protocols that should be enabled for the
792   *                    socket, if available.
793   *
794   * @throws  IOException  If a problem is encountered while applying the
795   *                       desired set of enabled protocols to the given socket.
796   */
797  static void applyEnabledSSLProtocols(@Nullable final Socket socket,
798                                       @NotNull final Set<String> protocols)
799       throws IOException
800  {
801    if ((socket == null) || (!(socket instanceof SSLSocket)) ||
802         protocols.isEmpty())
803    {
804      return;
805    }
806
807    final SSLSocket sslSocket = (SSLSocket) socket;
808    final String[] protocolsToEnable =
809         getSSLProtocolsToEnable(protocols, sslSocket.getSupportedProtocols());
810
811    try
812    {
813      sslSocket.setEnabledProtocols(protocolsToEnable);
814    }
815    catch (final Exception e)
816    {
817      Debug.debugException(e);
818    }
819  }
820
821
822
823  /**
824   * Updates the provided server socket to apply the appropriate set of enabled
825   * SSL protocols.  This will only have any effect for server sockets that are
826   * instances of {@code javax.net.ssl.SSLServerSocket}, but it is safe to call
827   * for any kind of {@code java.net.ServerSocket}.  This should be called
828   * before attempting any communication over the socket.
829   *
830   * @param  serverSocket  The server socket on which to apply the configured
831   *                       set of enabled SSL protocols.
832   * @param  protocols     The set of protocols that should be enabled for the
833   *                       server socket, if available.
834   *
835   * @throws  IOException  If a problem is encountered while applying the
836   *                       desired set of enabled protocols to the given server
837   *                       socket.
838   */
839  static void applyEnabledSSLProtocols(
840                   @Nullable final ServerSocket serverSocket,
841                   @NotNull final Set<String> protocols)
842       throws IOException
843  {
844    if ((serverSocket == null) ||
845         (!(serverSocket instanceof SSLServerSocket)) ||
846         protocols.isEmpty())
847    {
848      return;
849    }
850
851    final SSLServerSocket sslServerSocket = (SSLServerSocket) serverSocket;
852    final String[] protocolsToEnable = getSSLProtocolsToEnable(protocols,
853         sslServerSocket.getSupportedProtocols());
854
855    try
856    {
857      sslServerSocket.setEnabledProtocols(protocolsToEnable);
858    }
859    catch (final Exception e)
860    {
861      Debug.debugException(e);
862    }
863  }
864
865
866
867  /**
868   * Retrieves the names of the SSL protocols that should be enabled given the
869   * provided information.
870   *
871   * @param  desiredProtocols    The set of protocols that are desired to be
872   *                             enabled.
873   * @param  supportedProtocols  The set of all protocols that are supported.
874   *
875   * @return  The names of the SSL protocols that should be enabled.
876   *
877   * @throws  IOException  If none of the desired values are included in the
878   *                       supported set.
879   */
880  @NotNull()
881  private static String[] getSSLProtocolsToEnable(
882                               @NotNull final Set<String> desiredProtocols,
883                               @NotNull final String[] supportedProtocols)
884          throws IOException
885  {
886    final Set<String> lowerProtocols = new LinkedHashSet<>(
887         StaticUtils.computeMapCapacity(desiredProtocols.size()));
888    for (final String s : desiredProtocols)
889    {
890      lowerProtocols.add(StaticUtils.toLowerCase(s));
891    }
892
893    final ArrayList<String> enabledList =
894         new ArrayList<>(supportedProtocols.length);
895    for (final String supportedProtocol : supportedProtocols)
896    {
897      if (lowerProtocols.contains(StaticUtils.toLowerCase(supportedProtocol)))
898      {
899        enabledList.add(supportedProtocol);
900      }
901    }
902
903    if (enabledList.isEmpty())
904    {
905      final StringBuilder enabledBuffer = new StringBuilder();
906      final Iterator<String> enabledIterator = desiredProtocols.iterator();
907      while (enabledIterator.hasNext())
908      {
909        enabledBuffer.append('\'');
910        enabledBuffer.append(enabledIterator.next());
911        enabledBuffer.append('\'');
912
913        if (enabledIterator.hasNext())
914        {
915          enabledBuffer.append(", ");
916        }
917      }
918
919      final StringBuilder supportedBuffer = new StringBuilder();
920      for (int i=0; i < supportedProtocols.length; i++)
921      {
922        if (i > 0)
923        {
924          supportedBuffer.append(", ");
925        }
926
927        supportedBuffer.append('\'');
928        supportedBuffer.append(supportedProtocols[i]);
929        supportedBuffer.append('\'');
930      }
931
932      throw new IOException(
933           ERR_NO_ENABLED_SSL_PROTOCOLS_AVAILABLE_FOR_SOCKET.get(
934                enabledBuffer.toString(), supportedBuffer.toString(),
935                PROPERTY_ENABLED_SSL_PROTOCOLS,
936                SSLUtil.class.getName() + ".setEnabledSSLProtocols"));
937    }
938    else
939    {
940      return enabledList.toArray(StaticUtils.NO_STRINGS);
941    }
942  }
943
944
945
946  /**
947   * Retrieves the set of SSL cipher suites that will be enabled for use, if
948   * available, for SSL sockets created within the LDAP SDK.
949   *
950   * @return  The set of SSL cipher suites that will be enabled for use, if
951   *          available, for SSL sockets created within the LDAP SDK.
952   */
953  @NotNull()
954  public static Set<String> getEnabledSSLCipherSuites()
955  {
956    return ENABLED_SSL_CIPHER_SUITES.get();
957  }
958
959
960
961  /**
962   * Specifies the set of SSL cipher suites that will be enabled for SSL sockets
963   * created within the LDAP SDK.  When creating an SSL socket, the
964   * {@code SSLSocket.getSupportedCipherSuites} method will be used to determine
965   * which cipher suites are supported for that socket, and then the
966   * {@code SSLSocket.setEnabledCipherSuites} method will be used to enable
967   * those suites which are listed as both supported by the socket and included
968   * in this set.  If the provided set is {@code null} or empty, then the
969   * default set of enabled cipher suites will be used.
970   *
971   * @param  enabledSSLCipherSuites  The set of SSL cipher suites that will be
972   *                                 enabled for use for SSL sockets created
973   *                                 within the LDAP SDK.  It may be
974   *                                 {@code null} or empty to indicate that the
975   *                                 JDK-default set of enabled cipher suites
976   *                                 should be used for the socket.
977   */
978  public static void setEnabledSSLCipherSuites(
979              @Nullable final Collection<String> enabledSSLCipherSuites)
980  {
981    if (enabledSSLCipherSuites == null)
982    {
983      ENABLED_SSL_CIPHER_SUITES.set(Collections.<String>emptySet());
984    }
985    else
986    {
987      ENABLED_SSL_CIPHER_SUITES.set(Collections.unmodifiableSet(
988           new LinkedHashSet<>(enabledSSLCipherSuites)));
989    }
990  }
991
992
993
994  /**
995   * Updates the provided socket to apply the appropriate set of enabled SSL
996   * cipher suites.  This will only have any effect for sockets that are
997   * instances of {@code javax.net.ssl.SSLSocket}, but it is safe to call for
998   * any kind of {@code java.net.Socket}.  This should be called before
999   * attempting any communication over the socket.
1000   *
1001   * @param  socket  The socket on which to apply the configured set of enabled
1002   *                 SSL cipher suites.
1003   *
1004   * @throws  LDAPException  If {@link #getEnabledSSLCipherSuites} returns a
1005   *                         non-empty set but none of the values in that set
1006   *                         are supported by the socket.
1007   */
1008  public static void applyEnabledSSLCipherSuites(@NotNull final Socket socket)
1009         throws LDAPException
1010  {
1011    try
1012    {
1013      applyEnabledSSLCipherSuites(socket, ENABLED_SSL_CIPHER_SUITES.get());
1014    }
1015    catch (final IOException ioe)
1016    {
1017      Debug.debugException(ioe);
1018      throw new LDAPException(ResultCode.CONNECT_ERROR, ioe.getMessage(), ioe);
1019    }
1020  }
1021
1022
1023
1024  /**
1025   * Updates the provided socket to apply the appropriate set of enabled SSL
1026   * cipher suites.  This will only have any effect for sockets that are
1027   * instances of {@code javax.net.ssl.SSLSocket}, but it is safe to call for
1028   * any kind of {@code java.net.Socket}.  This should be called before
1029   * attempting any communication over the socket.
1030   *
1031   * @param  socket        The socket on which to apply the configured set of
1032   *                       enabled SSL cipher suites.
1033   * @param  cipherSuites  The set of cipher suites that should be enabled for
1034   *                       the socket, if available.
1035   *
1036   * @throws  IOException  If a problem is encountered while applying the
1037   *                       desired set of enabled cipher suites to the given
1038   *                       socket.
1039   */
1040  static void applyEnabledSSLCipherSuites(@Nullable final Socket socket,
1041                   @NotNull final Set<String> cipherSuites)
1042         throws IOException
1043  {
1044    if ((socket == null) || (!(socket instanceof SSLSocket)) ||
1045        cipherSuites.isEmpty())
1046    {
1047      return;
1048    }
1049
1050    final SSLSocket sslSocket = (SSLSocket) socket;
1051    final String[] cipherSuitesToEnable =
1052         getSSLCipherSuitesToEnable(cipherSuites,
1053              sslSocket.getSupportedCipherSuites());
1054
1055    try
1056    {
1057      sslSocket.setEnabledCipherSuites(cipherSuitesToEnable);
1058    }
1059    catch (final Exception e)
1060    {
1061      Debug.debugException(e);
1062    }
1063  }
1064
1065
1066
1067  /**
1068   * Updates the provided server socket to apply the appropriate set of enabled
1069   * SSL cipher suites.  This will only have any effect for server sockets that
1070   * are instances of {@code javax.net.ssl.SSLServerSocket}, but it is safe to
1071   * call for any kind of {@code java.net.ServerSocket}.  This should be called
1072   * before attempting any communication over the socket.
1073   *
1074   * @param  serverSocket     The server socket on which to apply the configured
1075   *                          set of enabled SSL cipher suites.
1076   * @param  cipherSuites     The set of cipher suites that should be enabled
1077   *                          for the server socket, if available.
1078   *
1079   * @throws  IOException  If a problem is encountered while applying the
1080   *                       desired set of enabled cipher suites to the given
1081   *                       server socket.
1082   */
1083  static void applyEnabledSSLCipherSuites(
1084                   @Nullable final ServerSocket serverSocket,
1085                   @NotNull final Set<String> cipherSuites)
1086         throws IOException
1087  {
1088    if ((serverSocket == null) ||
1089        (! (serverSocket instanceof SSLServerSocket)) ||
1090        cipherSuites.isEmpty())
1091    {
1092      return;
1093    }
1094
1095    final SSLServerSocket sslServerSocket = (SSLServerSocket) serverSocket;
1096    final String[] cipherSuitesToEnable =
1097         getSSLCipherSuitesToEnable(cipherSuites,
1098         sslServerSocket.getSupportedCipherSuites());
1099
1100    try
1101    {
1102      sslServerSocket.setEnabledCipherSuites(cipherSuitesToEnable);
1103    }
1104    catch (final Exception e)
1105    {
1106      Debug.debugException(e);
1107    }
1108  }
1109
1110
1111
1112  /**
1113   * Retrieves the names of the SSL cipher suites that should be enabled given
1114   * the provided information.
1115   *
1116   * @param  desiredCipherSuites    The set of cipher suites that are desired to
1117   *                                be enabled.
1118   * @param  supportedCipherSuites  The set of all cipher suites that are
1119   *                                supported.
1120   *
1121   * @return  The names of the SSL cipher suites that should be enabled.
1122   *
1123   * @throws  IOException  If none of the desired values are included in the
1124   *                       supported set.
1125   */
1126  @NotNull()
1127  private static String[] getSSLCipherSuitesToEnable(
1128                               @NotNull final Set<String> desiredCipherSuites,
1129                               @NotNull final String[] supportedCipherSuites)
1130         throws IOException
1131  {
1132    final Set<String> upperCipherSuites = new LinkedHashSet<>(
1133         StaticUtils.computeMapCapacity(desiredCipherSuites.size()));
1134    for (final String s : desiredCipherSuites)
1135    {
1136      upperCipherSuites.add(StaticUtils.toUpperCase(s));
1137    }
1138
1139    final ArrayList<String> enabledList =
1140         new ArrayList<>(supportedCipherSuites.length);
1141    for (final String supportedCipherSuite : supportedCipherSuites)
1142    {
1143      if (upperCipherSuites.contains(StaticUtils.toUpperCase(
1144           supportedCipherSuite)))
1145      {
1146        enabledList.add(supportedCipherSuite);
1147      }
1148    }
1149
1150    if (enabledList.isEmpty())
1151    {
1152      final StringBuilder enabledBuffer = new StringBuilder();
1153      final Iterator<String> enabledIterator = desiredCipherSuites.iterator();
1154      while (enabledIterator.hasNext())
1155      {
1156        enabledBuffer.append('\'');
1157        enabledBuffer.append(enabledIterator.next());
1158        enabledBuffer.append('\'');
1159
1160        if (enabledIterator.hasNext())
1161        {
1162          enabledBuffer.append(", ");
1163        }
1164      }
1165
1166      final StringBuilder supportedBuffer = new StringBuilder();
1167      for (int i=0; i < supportedCipherSuites.length; i++)
1168      {
1169        if (i > 0)
1170        {
1171          supportedBuffer.append(", ");
1172        }
1173
1174        supportedBuffer.append('\'');
1175        supportedBuffer.append(supportedCipherSuites[i]);
1176        supportedBuffer.append('\'');
1177      }
1178
1179      throw new IOException(
1180           ERR_NO_ENABLED_SSL_CIPHER_SUITES_AVAILABLE_FOR_SOCKET.get(
1181                enabledBuffer.toString(), supportedBuffer.toString(),
1182                PROPERTY_ENABLED_SSL_CIPHER_SUITES,
1183                SSLUtil.class.getName() + ".setEnabledSSLCipherSuites"));
1184    }
1185    else
1186    {
1187      return enabledList.toArray(StaticUtils.NO_STRINGS);
1188    }
1189  }
1190
1191
1192
1193  /**
1194   * Configures SSL default settings for the LDAP SDK.  This method is
1195   * non-private for purposes of easier test coverage.
1196   */
1197  static void configureSSLDefaults()
1198  {
1199    // See if there is a system property that specifies what the default SSL
1200    // protocol should be.  If not, then try to dynamically determine it.
1201    final String defaultPropValue =
1202         StaticUtils.getSystemProperty(PROPERTY_DEFAULT_SSL_PROTOCOL);
1203    if ((defaultPropValue != null) && (! defaultPropValue.isEmpty()))
1204    {
1205      DEFAULT_SSL_PROTOCOL.set(defaultPropValue);
1206    }
1207    else
1208    {
1209      // We should be able to discover the SSL protocol that offers the best mix
1210      // of security and compatibility.  If we see that TLSv1.1, TLSv1.2, and/or
1211      // TLSv1.3 are available, then we'll add those to the set of default
1212      // enabled protocols.
1213      try
1214      {
1215        final SSLContext defaultContext = SSLContext.getDefault();
1216        final String[] supportedProtocols =
1217             defaultContext.getSupportedSSLParameters().getProtocols();
1218
1219        final LinkedHashSet<String> protocolMap =
1220             new LinkedHashSet<>(Arrays.asList(supportedProtocols));
1221        if (protocolMap.contains(SSL_PROTOCOL_TLS_1_3))
1222        {
1223          DEFAULT_SSL_PROTOCOL.set(SSL_PROTOCOL_TLS_1_3);
1224        }
1225        else if (protocolMap.contains(SSL_PROTOCOL_TLS_1_2))
1226        {
1227          DEFAULT_SSL_PROTOCOL.set(SSL_PROTOCOL_TLS_1_2);
1228        }
1229        else if (protocolMap.contains(SSL_PROTOCOL_TLS_1_1))
1230        {
1231          DEFAULT_SSL_PROTOCOL.set(SSL_PROTOCOL_TLS_1_1);
1232        }
1233        else if (protocolMap.contains(SSL_PROTOCOL_TLS_1))
1234        {
1235          DEFAULT_SSL_PROTOCOL.set(SSL_PROTOCOL_TLS_1);
1236        }
1237      }
1238      catch (final Exception e)
1239      {
1240        Debug.debugException(e);
1241      }
1242    }
1243
1244    // A set to use for the default set of enabled protocols.  Unless otherwise
1245    // specified via system property, we'll always enable TLSv1.  We may enable
1246    // other protocols based on the default protocol.  The default set of
1247    // enabled protocols will not include SSLv3 even if the JVM might otherwise
1248    // include it as a default enabled protocol because of known security
1249    // problems with SSLv3.
1250    final LinkedHashSet<String> enabledProtocols =
1251         new LinkedHashSet<>(StaticUtils.computeMapCapacity(10));
1252    if (DEFAULT_SSL_PROTOCOL.get().equals(SSL_PROTOCOL_TLS_1_3))
1253    {
1254      enabledProtocols.add(SSL_PROTOCOL_TLS_1_3);
1255      enabledProtocols.add(SSL_PROTOCOL_TLS_1_2);
1256      enabledProtocols.add(SSL_PROTOCOL_TLS_1_1);
1257    }
1258    else if (DEFAULT_SSL_PROTOCOL.get().equals(SSL_PROTOCOL_TLS_1_2))
1259    {
1260      enabledProtocols.add(SSL_PROTOCOL_TLS_1_2);
1261      enabledProtocols.add(SSL_PROTOCOL_TLS_1_1);
1262    }
1263    else if (DEFAULT_SSL_PROTOCOL.get().equals(SSL_PROTOCOL_TLS_1_1))
1264    {
1265      enabledProtocols.add(SSL_PROTOCOL_TLS_1_1);
1266    }
1267    enabledProtocols.add(SSL_PROTOCOL_TLS_1);
1268
1269    // If there is a system property that specifies which enabled SSL protocols
1270    // to use, then it will override the defaults.
1271    String enabledPropValue =
1272         StaticUtils.getSystemProperty(PROPERTY_ENABLED_SSL_PROTOCOLS);
1273    if ((enabledPropValue != null) && (! enabledPropValue.isEmpty()))
1274    {
1275      enabledProtocols.clear();
1276
1277      final StringTokenizer tokenizer = new StringTokenizer(enabledPropValue,
1278           ", ", false);
1279      while (tokenizer.hasMoreTokens())
1280      {
1281        final String token = tokenizer.nextToken();
1282        if (! token.isEmpty())
1283        {
1284          enabledProtocols.add(token);
1285        }
1286      }
1287    }
1288
1289    ENABLED_SSL_PROTOCOLS.set(Collections.unmodifiableSet(enabledProtocols));
1290
1291
1292    // Use the TLS cipher suite selector to set the default set of enabled
1293    // cipher suites for any SSL sockets that are created.
1294    ENABLED_SSL_CIPHER_SUITES.set(
1295         TLSCipherSuiteSelector.getRecommendedCipherSuites());
1296
1297
1298    // If there is a system property that specifies which SSL cipher suites to
1299    // use, then it wil override the defaults.
1300    enabledPropValue =
1301         StaticUtils.getSystemProperty(PROPERTY_ENABLED_SSL_CIPHER_SUITES);
1302    if ((enabledPropValue != null) && (! enabledPropValue.isEmpty()))
1303    {
1304      final LinkedHashSet<String> enabledCipherSuites =
1305           new LinkedHashSet<>(StaticUtils.computeMapCapacity(50));
1306
1307      final StringTokenizer tokenizer = new StringTokenizer(enabledPropValue,
1308           ", ", false);
1309      while (tokenizer.hasMoreTokens())
1310      {
1311        final String token = tokenizer.nextToken();
1312        if (! token.isEmpty())
1313        {
1314          enabledCipherSuites.add(token);
1315        }
1316      }
1317
1318      if (! enabledCipherSuites.isEmpty())
1319      {
1320        ENABLED_SSL_CIPHER_SUITES.set(
1321             Collections.unmodifiableSet(enabledCipherSuites));
1322      }
1323    }
1324  }
1325
1326
1327
1328  /**
1329   * Creates a string representation of the provided certificate.
1330   *
1331   * @param  certificate  The certificate for which to generate the string
1332   *                      representation.  It must not be {@code null}.
1333   *
1334   * @return  A string representation of the provided certificate.
1335   */
1336  @NotNull()
1337  public static String certificateToString(
1338                            @NotNull final X509Certificate certificate)
1339  {
1340    final StringBuilder buffer = new StringBuilder();
1341    certificateToString(certificate, buffer);
1342    return buffer.toString();
1343  }
1344
1345
1346
1347  /**
1348   * Appends a string representation of the provided certificate to the given
1349   * buffer.
1350   *
1351   * @param  certificate  The certificate for which to generate the string
1352   *                      representation.  It must not be {@code null}.
1353   * @param  buffer       The buffer to which to append the string
1354   *                      representation.
1355   */
1356  public static void certificateToString(
1357                          @NotNull final X509Certificate certificate,
1358                          @NotNull final StringBuilder buffer)
1359  {
1360    buffer.append("Certificate(subject='");
1361    buffer.append(
1362         certificate.getSubjectX500Principal().getName(X500Principal.RFC2253));
1363    buffer.append("', serialNumber=");
1364    buffer.append(certificate.getSerialNumber());
1365    buffer.append(", notBefore=");
1366    StaticUtils.encodeGeneralizedTime(certificate.getNotBefore());
1367    buffer.append(", notAfter=");
1368    StaticUtils.encodeGeneralizedTime(certificate.getNotAfter());
1369    buffer.append(", signatureAlgorithm='");
1370    buffer.append(certificate.getSigAlgName());
1371    buffer.append("', signatureBytes='");
1372    StaticUtils.toHex(certificate.getSignature(), buffer);
1373    buffer.append("', issuerSubject='");
1374    buffer.append(
1375         certificate.getIssuerX500Principal().getName(X500Principal.RFC2253));
1376    buffer.append("')");
1377  }
1378}