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    }