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