001 /*
002 * Copyright 2008-2014 UnboundID Corp.
003 * All Rights Reserved.
004 */
005 /*
006 * Copyright (C) 2008-2014 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021 package com.unboundid.util.ssl;
022
023
024
025 import java.lang.reflect.Method;
026 import java.security.GeneralSecurityException;
027 import java.util.Arrays;
028 import java.util.HashSet;
029 import java.util.concurrent.atomic.AtomicReference;
030 import javax.net.ssl.KeyManager;
031 import javax.net.ssl.SSLContext;
032 import javax.net.ssl.SSLSocketFactory;
033 import javax.net.ssl.SSLServerSocketFactory;
034 import javax.net.ssl.TrustManager;
035
036 import com.unboundid.util.Debug;
037 import com.unboundid.util.ThreadSafety;
038 import com.unboundid.util.ThreadSafetyLevel;
039
040 import 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)
106 public 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 }