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