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