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