001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
010 * or http://forgerock.org/license/CDDLv1.0.html.
011 * See the License for the specific language governing permissions
012 * and limitations under the License.
013 *
014 * When distributing Covered Code, include this CDDL HEADER in each
015 * file and include the License file at legal-notices/CDDLv1_0.txt.
016 * If applicable, add the following below this CDDL HEADER, with the
017 * fields enclosed by brackets "[]" replaced with your own identifying
018 * information:
019 *      Portions Copyright [yyyy] [name of copyright owner]
020 *
021 * CDDL HEADER END
022 *
023 *
024 *      Copyright 2010 Sun Microsystems, Inc.
025 */
026
027package org.forgerock.opendj.ldap;
028
029import java.security.GeneralSecurityException;
030import java.security.Provider;
031import java.security.SecureRandom;
032
033import javax.net.ssl.KeyManager;
034import javax.net.ssl.SSLContext;
035import javax.net.ssl.TrustManager;
036
037/**
038 * An SSL context builder provides an interface for incrementally constructing
039 * {@link SSLContext} instances for use when securing connections with SSL or
040 * the StartTLS extended operation. The {@link #getSSLContext()} should be
041 * called in order to obtain the {@code SSLContext}.
042 * <p>
043 * For example, use the SSL context builder when setting up LDAP options needed
044 * to use StartTLS. {@link org.forgerock.opendj.ldap.TrustManagers
045 * TrustManagers} has methods you can use to set the trust manager for the SSL
046 * context builder.
047 *
048 * <pre>
049 * LDAPOptions options = new LDAPOptions();
050 * SSLContext sslContext =
051 *         new SSLContextBuilder().setTrustManager(...).getSSLContext();
052 * options.setSSLContext(sslContext);
053 * options.setUseStartTLS(true);
054 *
055 * String host = ...;
056 * int port = ...;
057 * LDAPConnectionFactory factory = new LDAPConnectionFactory(host, port, options);
058 * Connection connection = factory.getConnection();
059 * // Connection uses StartTLS...
060 * </pre>
061 */
062public final class SSLContextBuilder {
063
064    /**
065     * SSL protocol: supports some version of SSL; may support other versions.
066     */
067    public static final String PROTOCOL_SSL = "SSL";
068
069    /**
070     * SSL protocol: supports SSL version 2 or higher; may support other
071     * versions.
072     */
073    public static final String PROTOCOL_SSL2 = "SSLv2";
074
075    /**
076     * SSL protocol: supports SSL version 3; may support other versions.
077     */
078    public static final String PROTOCOL_SSL3 = "SSLv3";
079
080    /**
081     * SSL protocol: supports some version of TLS; may support other versions.
082     */
083    public static final String PROTOCOL_TLS = "TLS";
084
085    /**
086     * SSL protocol: supports RFC 2246: TLS version 1.0 ; may support other
087     * versions.
088     */
089    public static final String PROTOCOL_TLS1 = "TLSv1";
090
091    /**
092     * SSL protocol: supports RFC 4346: TLS version 1.1 ; may support other
093     * versions.
094     */
095    public static final String PROTOCOL_TLS1_1 = "TLSv1.1";
096
097    private TrustManager trustManager;
098    private KeyManager keyManager;
099    private String protocol = PROTOCOL_TLS1;
100    private SecureRandom random;
101
102    /** These are mutually exclusive. */
103    private Provider provider;
104    private String providerName;
105
106    /**
107     * Creates a new SSL context builder using default parameters.
108     */
109    public SSLContextBuilder() {
110        // Do nothing.
111    }
112
113    /**
114     * Creates a {@code SSLContext} using the parameters of this SSL context
115     * builder.
116     *
117     * @return A {@code SSLContext} using the parameters of this SSL context
118     *         builder.
119     * @throws GeneralSecurityException
120     *             If the SSL context could not be created, perhaps due to
121     *             missing algorithms.
122     */
123    public SSLContext getSSLContext() throws GeneralSecurityException {
124        TrustManager[] tm = null;
125        if (trustManager != null) {
126            tm = new TrustManager[] { trustManager };
127        }
128
129        KeyManager[] km = null;
130        if (keyManager != null) {
131            km = new KeyManager[] { keyManager };
132        }
133
134        SSLContext sslContext;
135        if (provider != null) {
136            sslContext = SSLContext.getInstance(protocol, provider);
137        } else if (providerName != null) {
138            sslContext = SSLContext.getInstance(protocol, providerName);
139        } else {
140            sslContext = SSLContext.getInstance(protocol);
141        }
142        sslContext.init(km, tm, random);
143
144        return sslContext;
145    }
146
147    /**
148     * Sets the key manager which the SSL context should use. By default, no key
149     * manager is specified indicating that no certificates will be used.
150     *
151     * @param keyManager
152     *            The key manager which the SSL context should use, which may be
153     *            {@code null} indicating that no certificates will be used.
154     * @return This SSL context builder.
155     */
156    public SSLContextBuilder setKeyManager(final KeyManager keyManager) {
157        this.keyManager = keyManager;
158        return this;
159    }
160
161    /**
162     * Sets the protocol which the SSL context should use. By default, TLSv1
163     * will be used.
164     *
165     * @param protocol
166     *            The protocol which the SSL context should use, which may be
167     *            {@code null} indicating that TLSv1 will be used.
168     * @return This SSL context builder.
169     */
170    public SSLContextBuilder setProtocol(final String protocol) {
171        this.protocol = protocol;
172        return this;
173    }
174
175    /**
176     * Sets the provider which the SSL context should use. By default, the
177     * default provider associated with this JVM will be used.
178     *
179     * @param provider
180     *            The provider which the SSL context should use, which may be
181     *            {@code null} indicating that the default provider associated
182     *            with this JVM will be used.
183     * @return This SSL context builder.
184     */
185    public SSLContextBuilder setProvider(final Provider provider) {
186        this.provider = provider;
187        this.providerName = null;
188        return this;
189    }
190
191    /**
192     * Sets the provider which the SSL context should use. By default, the
193     * default provider associated with this JVM will be used.
194     *
195     * @param providerName
196     *            The name of the provider which the SSL context should use,
197     *            which may be {@code null} indicating that the default provider
198     *            associated with this JVM will be used.
199     * @return This SSL context builder.
200     */
201    public SSLContextBuilder setProvider(final String providerName) {
202        this.provider = null;
203        this.providerName = providerName;
204        return this;
205    }
206
207    /**
208     * Sets the secure random number generator which the SSL context should use.
209     * By default, the default secure random number generator associated with
210     * this JVM will be used.
211     *
212     * @param random
213     *            The secure random number generator which the SSL context
214     *            should use, which may be {@code null} indicating that the
215     *            default secure random number generator associated with this
216     *            JVM will be used.
217     * @return This SSL context builder.
218     */
219    public SSLContextBuilder setSecureRandom(final SecureRandom random) {
220        this.random = random;
221        return this;
222    }
223
224    /**
225     * Sets the trust manager which the SSL context should use. By default, no
226     * trust manager is specified indicating that only certificates signed by
227     * the authorities associated with this JVM will be accepted.
228     *
229     * @param trustManager
230     *            The trust manager which the SSL context should use, which may
231     *            be {@code null} indicating that only certificates signed by
232     *            the authorities associated with this JVM will be accepted.
233     * @return This SSL context builder.
234     */
235    public SSLContextBuilder setTrustManager(final TrustManager trustManager) {
236        this.trustManager = trustManager;
237        return this;
238    }
239}