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 }