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 */ 021package com.unboundid.util.ssl; 022 023 024 025import java.lang.reflect.Method; 026import java.net.Socket; 027import java.security.GeneralSecurityException; 028import java.util.ArrayList; 029import java.util.Arrays; 030import java.util.Collection; 031import java.util.Collections; 032import java.util.HashSet; 033import java.util.Iterator; 034import java.util.Set; 035import java.util.StringTokenizer; 036import java.util.concurrent.atomic.AtomicReference; 037import javax.net.ssl.KeyManager; 038import javax.net.ssl.SSLContext; 039import javax.net.ssl.SSLSocket; 040import javax.net.ssl.SSLSocketFactory; 041import javax.net.ssl.SSLServerSocketFactory; 042import javax.net.ssl.TrustManager; 043 044import com.unboundid.ldap.sdk.LDAPException; 045import com.unboundid.ldap.sdk.ResultCode; 046import com.unboundid.util.Debug; 047import com.unboundid.util.StaticUtils; 048import com.unboundid.util.ThreadSafety; 049import com.unboundid.util.ThreadSafetyLevel; 050 051import static com.unboundid.util.Validator.*; 052import 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) 118public 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}