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