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