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