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