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.security.GeneralSecurityException; 027import java.util.Arrays; 028import java.util.HashSet; 029import java.util.concurrent.atomic.AtomicReference; 030import javax.net.ssl.KeyManager; 031import javax.net.ssl.SSLContext; 032import javax.net.ssl.SSLSocketFactory; 033import javax.net.ssl.SSLServerSocketFactory; 034import javax.net.ssl.TrustManager; 035 036import com.unboundid.util.Debug; 037import com.unboundid.util.ThreadSafety; 038import com.unboundid.util.ThreadSafetyLevel; 039 040import static com.unboundid.util.Validator.*; 041 042 043 044/** 045 * This class provides a simple interface for creating {@code SSLContext} and 046 * {@code SSLSocketFactory} instances, which may be used to create SSL-based 047 * connections, or secure existing connections with StartTLS. 048 * <BR><BR> 049 * <H2>Example 1</H2> 050 * The following example demonstrates the use of the SSL helper to create an 051 * SSL-based LDAP connection that will blindly trust any certificate that the 052 * server presents. Using the {@code TrustAllTrustManager} is only recommended 053 * for testing purposes, since blindly trusting any certificate is not secure. 054 * <PRE> 055 * // Create an SSLUtil instance that is configured to trust any certificate, 056 * // and use it to create a socket factory. 057 * SSLUtil sslUtil = new SSLUtil(new TrustAllTrustManager()); 058 * SSLSocketFactory sslSocketFactory = sslUtil.createSSLSocketFactory(); 059 * 060 * // Establish a secure connection using the socket factory. 061 * LDAPConnection connection = new LDAPConnection(sslSocketFactory); 062 * connection.connect(serverAddress, serverSSLPort); 063 * 064 * // Process operations using the connection.... 065 * RootDSE rootDSE = connection.getRootDSE(); 066 * 067 * connection.close(); 068 * </PRE> 069 * <BR> 070 * <H2>Example 2</H2> 071 * The following example demonstrates the use of the SSL helper to create a 072 * non-secure LDAP connection and then use the StartTLS extended operation to 073 * secure it. It will use a trust store to determine whether to trust the 074 * server certificate. 075 * <PRE> 076 * // Establish a non-secure connection to the server. 077 * LDAPConnection connection = new LDAPConnection(serverAddress, serverPort); 078 * 079 * // Create an SSLUtil instance that is configured to trust certificates in 080 * // a specified trust store file, and use it to create an SSLContext that 081 * // will be used for StartTLS processing. 082 * SSLUtil sslUtil = new SSLUtil(new TrustStoreTrustManager(trustStorePath)); 083 * SSLContext sslContext = sslUtil.createSSLContext(); 084 * 085 * // Use the StartTLS extended operation to secure the connection. 086 * StartTLSExtendedRequest startTLSRequest = 087 * new StartTLSExtendedRequest(sslContext); 088 * ExtendedResult startTLSResult; 089 * try 090 * { 091 * startTLSResult = connection.processExtendedOperation(startTLSRequest); 092 * } 093 * catch (LDAPException le) 094 * { 095 * startTLSResult = new ExtendedResult(le); 096 * } 097 * LDAPTestUtils.assertResultCodeEquals(startTLSResult, ResultCode.SUCCESS); 098 * 099 * // Process operations using the connection.... 100 * RootDSE rootDSE = connection.getRootDSE(); 101 * 102 * connection.close(); 103 * </PRE> 104 */ 105@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 106public final class SSLUtil 107{ 108 /** 109 * The name of the system property that can be used to specify the initial 110 * value for the default SSL protocol that should be used. If this is not 111 * set, then the default SSL protocol will be dynamically determined. This 112 * can be overridden via the {@link #setDefaultSSLProtocol(String)} method. 113 */ 114 public static final String PROPERTY_DEFAULT_SSL_PROTOCOL = 115 "com.unboundid.util.SSLUtil.defaultSSLProtocol"; 116 117 118 119 /** 120 * The default protocol string that will be used to create SSL contexts when 121 * no explicit protocol is specified. 122 */ 123 private static final AtomicReference<String> DEFAULT_SSL_PROTOCOL = 124 new AtomicReference<String>("TLSv1"); 125 126 static 127 { 128 // See if there is a system property that specifies what the default SSL 129 // protocol should be. If not, then try to dynamically determine it. 130 final String propValue = System.getProperty(PROPERTY_DEFAULT_SSL_PROTOCOL); 131 if ((propValue != null) && (propValue.length() > 0)) 132 { 133 DEFAULT_SSL_PROTOCOL.set(propValue); 134 } 135 else 136 { 137 // Ideally, we should be able to discover the SSL protocol that offers the 138 // best mix of security and compatibility. Unfortunately, Java SE 5 139 // doesn't expose the methods necessary to allow us to do that, but if the 140 // running JVM is Java SE 6 or later, then we can use reflection to invoke 141 // those methods and make the appropriate determination. 142 143 try 144 { 145 final Method getDefaultMethod = 146 SSLContext.class.getMethod("getDefault"); 147 final SSLContext defaultContext = 148 (SSLContext) getDefaultMethod.invoke(null); 149 150 final Method getSupportedParamsMethod = 151 SSLContext.class.getMethod("getSupportedSSLParameters"); 152 final Object paramsObj = 153 getSupportedParamsMethod.invoke(defaultContext); 154 155 final Class<?> sslParamsClass = 156 Class.forName("javax.net.ssl.SSLParameters"); 157 final Method getProtocolsMethod = 158 sslParamsClass.getMethod("getProtocols"); 159 final String[] supportedProtocols = 160 (String[]) getProtocolsMethod.invoke(paramsObj); 161 162 final HashSet<String> protocolMap = 163 new HashSet<String>(Arrays.asList(supportedProtocols)); 164 if (protocolMap.contains("TLSv1.2")) 165 { 166 DEFAULT_SSL_PROTOCOL.set("TLSv1.2"); 167 } 168 else if (protocolMap.contains("TLSv1.1")) 169 { 170 DEFAULT_SSL_PROTOCOL.set("TLSv1.1"); 171 } 172 else if (protocolMap.contains("TLSv1")) 173 { 174 DEFAULT_SSL_PROTOCOL.set("TLSv1"); 175 } 176 } 177 catch (final Exception e) 178 { 179 Debug.debugException(e); 180 } 181 } 182 } 183 184 185 186 // The set of key managers to be used. 187 private final KeyManager[] keyManagers; 188 189 // The set of trust managers to be used. 190 private final TrustManager[] trustManagers; 191 192 193 194 /** 195 * Creates a new SSLUtil instance that will not have a custom key manager or 196 * trust manager. It will not be able to provide a certificate to the server 197 * if one is requested, and it will only trust certificates signed by a 198 * predefined set of authorities. 199 */ 200 public SSLUtil() 201 { 202 keyManagers = null; 203 trustManagers = null; 204 } 205 206 207 208 /** 209 * Creates a new SSLUtil instance that will use the provided trust manager to 210 * determine whether to trust server certificates presented to the client. 211 * It will not be able to provide a certificate to the server if one is 212 * requested. 213 * 214 * @param trustManager The trust manager to use to determine whether to 215 * trust server certificates presented to the client. 216 * It may be {@code null} if the default set of trust 217 * managers should be used. 218 */ 219 public SSLUtil(final TrustManager trustManager) 220 { 221 keyManagers = null; 222 223 if (trustManager == null) 224 { 225 trustManagers = null; 226 } 227 else 228 { 229 trustManagers = new TrustManager[] { trustManager }; 230 } 231 } 232 233 234 235 /** 236 * Creates a new SSLUtil instance that will use the provided trust managers 237 * to determine whether to trust server certificates presented to the client. 238 * It will not be able to provide a certificate to the server if one is 239 * requested. 240 * 241 * @param trustManagers The set of trust managers to use to determine 242 * whether to trust server certificates presented to 243 * the client. It may be {@code null} or empty if the 244 * default set of trust managers should be used. 245 */ 246 public SSLUtil(final TrustManager[] trustManagers) 247 { 248 keyManagers = null; 249 250 if ((trustManagers == null) || (trustManagers.length == 0)) 251 { 252 this.trustManagers = null; 253 } 254 else 255 { 256 this.trustManagers = trustManagers; 257 } 258 } 259 260 261 262 /** 263 * Creates a new SSLUtil instance that will use the provided key manager to 264 * obtain certificates to present to the server, and the provided trust 265 * manager to determine whether to trust server certificates presented to the 266 * client. 267 * 268 * @param keyManager The key manager to use to obtain certificates to 269 * present to the server if requested. It may be 270 * {@code null} if no client certificates will be 271 * required or should be provided. 272 * @param trustManager The trust manager to use to determine whether to 273 * trust server certificates presented to the client. 274 * It may be {@code null} if the default set of trust 275 * managers should be used. 276 */ 277 public SSLUtil(final KeyManager keyManager, final TrustManager trustManager) 278 { 279 if (keyManager == null) 280 { 281 keyManagers = null; 282 } 283 else 284 { 285 keyManagers = new KeyManager[] { keyManager }; 286 } 287 288 if (trustManager == null) 289 { 290 trustManagers = null; 291 } 292 else 293 { 294 trustManagers = new TrustManager[] { trustManager }; 295 } 296 } 297 298 299 300 /** 301 * Creates a new SSLUtil instance that will use the provided key managers to 302 * obtain certificates to present to the server, and the provided trust 303 * managers to determine whether to trust server certificates presented to the 304 * client. 305 * 306 * @param keyManagers The set of key managers to use to obtain 307 * certificates to present to the server if requested. 308 * It may be {@code null} or empty if no client 309 * certificates will be required or should be provided. 310 * @param trustManagers The set of trust managers to use to determine 311 * whether to trust server certificates presented to 312 * the client. It may be {@code null} or empty if the 313 * default set of trust managers should be used. 314 */ 315 public SSLUtil(final KeyManager[] keyManagers, 316 final TrustManager[] trustManagers) 317 { 318 if ((keyManagers == null) || (keyManagers.length == 0)) 319 { 320 this.keyManagers = null; 321 } 322 else 323 { 324 this.keyManagers = keyManagers; 325 } 326 327 if ((trustManagers == null) || (trustManagers.length == 0)) 328 { 329 this.trustManagers = null; 330 } 331 else 332 { 333 this.trustManagers = trustManagers; 334 } 335 } 336 337 338 339 /** 340 * Retrieves the set of key managers configured for use by this class, if any. 341 * 342 * @return The set of key managers configured for use by this class, or 343 * {@code null} if none were provided. 344 */ 345 public KeyManager[] getKeyManagers() 346 { 347 return keyManagers; 348 } 349 350 351 352 /** 353 * Retrieves the set of trust managers configured for use by this class, if 354 * any. 355 * 356 * @return The set of trust managers configured for use by this class, or 357 * {@code null} if none were provided. 358 */ 359 public TrustManager[] getTrustManagers() 360 { 361 return trustManagers; 362 } 363 364 365 366 /** 367 * Creates an initialized SSL context created with the configured key and 368 * trust managers. It will use the protocol returned by the 369 * {@link #getDefaultSSLProtocol} method and the JVM-default provider. 370 * 371 * @return The created SSL context. 372 * 373 * @throws GeneralSecurityException If a problem occurs while creating or 374 * initializing the SSL context. 375 */ 376 public SSLContext createSSLContext() 377 throws GeneralSecurityException 378 { 379 return createSSLContext(DEFAULT_SSL_PROTOCOL.get()); 380 } 381 382 383 384 /** 385 * Creates an initialized SSL context created with the configured key and 386 * trust managers. It will use the default provider. 387 * 388 * @param protocol The protocol to use. As per the Java SE 6 Cryptography 389 * Architecture document, the set of supported protocols 390 * should include at least "SSLv3", "TLSv1", "TLSv1.1", and 391 * "SSLv2Hello". It must not be {@code null}. 392 * 393 * @return The created SSL context. 394 * 395 * @throws GeneralSecurityException If a problem occurs while creating or 396 * initializing the SSL context. 397 */ 398 public SSLContext createSSLContext(final String protocol) 399 throws GeneralSecurityException 400 { 401 ensureNotNull(protocol); 402 403 final SSLContext sslContext = SSLContext.getInstance(protocol); 404 sslContext.init(keyManagers, trustManagers, null); 405 return sslContext; 406 } 407 408 409 410 /** 411 * Creates an initialized SSL context created with the configured key and 412 * trust managers. 413 * 414 * @param protocol The protocol to use. As per the Java SE 6 Cryptography 415 * Architecture document, the set of supported protocols 416 * should include at least "SSLv3", "TLSv1", "TLSv1.1", and 417 * "SSLv2Hello". It must not be {@code null}. 418 * @param provider The name of the provider to use for cryptographic 419 * operations. It must not be {@code null}. 420 * 421 * @return The created SSL context. 422 * 423 * @throws GeneralSecurityException If a problem occurs while creating or 424 * initializing the SSL context. 425 */ 426 public SSLContext createSSLContext(final String protocol, 427 final String provider) 428 throws GeneralSecurityException 429 { 430 ensureNotNull(protocol, provider); 431 432 final SSLContext sslContext = SSLContext.getInstance(protocol, provider); 433 sslContext.init(keyManagers, trustManagers, null); 434 return sslContext; 435 } 436 437 438 439 /** 440 * Creates an SSL socket factory using the configured key and trust manager 441 * providers. It will use the protocol returned by the 442 * {@link #getDefaultSSLProtocol} method and the JVM-default provider. 443 * 444 * @return The created SSL socket factory. 445 * 446 * @throws GeneralSecurityException If a problem occurs while creating or 447 * initializing the SSL socket factory. 448 */ 449 public SSLSocketFactory createSSLSocketFactory() 450 throws GeneralSecurityException 451 { 452 return createSSLContext().getSocketFactory(); 453 } 454 455 456 457 /** 458 * Creates an SSL socket factory with the configured key and trust managers. 459 * It will use the default provider. 460 * 461 * @param protocol The protocol to use. As per the Java SE 6 Cryptography 462 * Architecture document, the set of supported protocols 463 * should include at least "SSLv3", "TLSv1", "TLSv1.1", and 464 * "SSLv2Hello". It must not be {@code null}. 465 * 466 * @return The created SSL socket factory. 467 * 468 * @throws GeneralSecurityException If a problem occurs while creating or 469 * initializing the SSL socket factory. 470 */ 471 public SSLSocketFactory createSSLSocketFactory(final String protocol) 472 throws GeneralSecurityException 473 { 474 return createSSLContext(protocol).getSocketFactory(); 475 } 476 477 478 479 /** 480 * Creates an SSL socket factory with the configured key and trust managers. 481 * 482 * @param protocol The protocol to use. As per the Java SE 6 Cryptography 483 * Architecture document, the set of supported protocols 484 * should include at least "SSLv3", "TLSv1", "TLSv1.1", and 485 * "SSLv2Hello". It must not be {@code null}. 486 * @param provider The name of the provider to use for cryptographic 487 * operations. It must not be {@code null}. 488 * 489 * @return The created SSL socket factory. 490 * 491 * @throws GeneralSecurityException If a problem occurs while creating or 492 * initializing the SSL socket factory. 493 */ 494 public SSLSocketFactory createSSLSocketFactory(final String protocol, 495 final String provider) 496 throws GeneralSecurityException 497 { 498 return createSSLContext(protocol, provider).getSocketFactory(); 499 } 500 501 502 503 /** 504 * Creates an SSL server socket factory using the configured key and trust 505 * manager providers. It will use the protocol returned by the 506 * {@link #getDefaultSSLProtocol} method and the JVM-default provider. 507 * 508 * @return The created SSL server socket factory. 509 * 510 * @throws GeneralSecurityException If a problem occurs while creating or 511 * initializing the SSL server socket 512 * factory. 513 */ 514 public SSLServerSocketFactory createSSLServerSocketFactory() 515 throws GeneralSecurityException 516 { 517 return createSSLContext().getServerSocketFactory(); 518 } 519 520 521 522 /** 523 * Creates an SSL server socket factory using the configured key and trust 524 * manager providers. It will use the JVM-default provider. 525 * 526 * @param protocol The protocol to use. As per the Java SE 6 Cryptography 527 * Architecture document, the set of supported protocols 528 * should include at least "SSLv3", "TLSv1", "TLSv1.1", and 529 * "SSLv2Hello". It must not be {@code null}. 530 * 531 * @return The created SSL server socket factory. 532 * 533 * @throws GeneralSecurityException If a problem occurs while creating or 534 * initializing the SSL server socket 535 * factory. 536 */ 537 public SSLServerSocketFactory createSSLServerSocketFactory( 538 final String protocol) 539 throws GeneralSecurityException 540 { 541 return createSSLContext(protocol).getServerSocketFactory(); 542 } 543 544 545 546 /** 547 * Creates an SSL server socket factory using the configured key and trust 548 * manager providers. 549 * 550 * @param protocol The protocol to use. As per the Java SE 6 Cryptography 551 * Architecture document, the set of supported protocols 552 * should include at least "SSLv3", "TLSv1", "TLSv1.1", and 553 * "SSLv2Hello". It must not be {@code null}. 554 * @param provider The name of the provider to use for cryptographic 555 * operations. It must not be {@code null}. 556 * 557 * @return The created SSL server socket factory. 558 * 559 * @throws GeneralSecurityException If a problem occurs while creating or 560 * initializing the SSL server socket 561 * factory. 562 */ 563 public SSLServerSocketFactory createSSLServerSocketFactory( 564 final String protocol, 565 final String provider) 566 throws GeneralSecurityException 567 { 568 return createSSLContext(protocol, provider).getServerSocketFactory(); 569 } 570 571 572 573 /** 574 * Retrieves the SSL protocol string that will be used by calls to 575 * {@link #createSSLContext()} that do not explicitly specify which protocol 576 * to use. 577 * 578 * @return The SSL protocol string that will be used by calls to create an 579 * SSL context that do not explicitly specify which protocol to use. 580 */ 581 public static String getDefaultSSLProtocol() 582 { 583 return DEFAULT_SSL_PROTOCOL.get(); 584 } 585 586 587 588 /** 589 * Specifies the SSL protocol string that will be used by calls to 590 * {@link #createSSLContext()} that do not explicitly specify which protocol 591 * to use. 592 * 593 * @param defaultSSLProtocol The SSL protocol string that will be used by 594 * calls to create an SSL context that do not 595 * explicitly specify which protocol to use. It 596 * must not be {@code null}. 597 */ 598 public static void setDefaultSSLProtocol(final String defaultSSLProtocol) 599 { 600 ensureNotNull(defaultSSLProtocol); 601 602 DEFAULT_SSL_PROTOCOL.set(defaultSSLProtocol); 603 } 604}