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