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