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