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