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