1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package javax.net.ssl;
19
20import java.security.KeyManagementException;
21import java.security.NoSuchAlgorithmException;
22import java.security.NoSuchProviderException;
23import java.security.Provider;
24import java.security.SecureRandom;
25import java.security.Security;
26import org.apache.harmony.security.fortress.Engine;
27
28
29/**
30 * The public API for secure socket protocol implementations. It acts as factory
31 * for {@code SSLSocketFactory}'s and {@code SSLEngine}s.
32 */
33public class SSLContext {
34    // StoreSSLContext service name
35    private static final String SERVICE = "SSLContext";
36
37    // Used to access common engine functionality
38    private static final Engine ENGINE = new Engine(SERVICE);
39
40    /**
41     * Default SSLContext that can be replaced with SSLContext.setDefault()
42     */
43    private static SSLContext DEFAULT;
44
45    /**
46     * Returns the default SSLContext.
47     *
48     * The default SSL context can be set with {@link #setDefault}. If
49     * not, one will be created with {@code
50     * SSLContext.getInstance("Default")}, which will already be
51     * initialized.
52     *
53     * @throws NoSuchAlgorithmException if there is a problem creating
54     * the default instance.
55     * @since 1.6
56     */
57    public static SSLContext getDefault() throws NoSuchAlgorithmException {
58        synchronized (ENGINE) {
59            if (DEFAULT == null) {
60                DEFAULT = SSLContext.getInstance("Default");
61            }
62            return DEFAULT;
63        }
64    }
65
66    /**
67     * Sets the default SSLContext instance as returned by {@link
68     * #getDefault()} to a non-null initialized value.
69     *
70     * @throws NullPointerException on a null argument
71     * @since 1.6
72     */
73    public static void setDefault(SSLContext sslContext) {
74        if (sslContext == null) {
75            throw new NullPointerException("sslContext == null");
76        }
77        synchronized (ENGINE) {
78            DEFAULT = sslContext;
79        }
80    }
81
82    /**
83     * Creates a new {@code SSLContext} instance for the specified protocol.
84     *
85     * @param protocol
86     *            the requested protocol to create a context for.
87     * @return the created {@code SSLContext} instance.
88     * @throws NoSuchAlgorithmException
89     *             if no installed provider can provide the requested protocol
90     * @throws NullPointerException
91     *             if {@code protocol} is {@code null} (instead of
92     *             NoSuchAlgorithmException as in 1.4 release)
93     */
94    public static SSLContext getInstance(String protocol) throws NoSuchAlgorithmException {
95        if (protocol == null) {
96            throw new NullPointerException("protocol == null");
97        }
98        Engine.SpiAndProvider sap = ENGINE.getInstance(protocol, null);
99        return new SSLContext((SSLContextSpi) sap.spi, sap.provider, protocol);
100    }
101
102    /**
103     * Creates a new {@code SSLContext} instance for the specified protocol from
104     * the specified provider.
105     *
106     * @param protocol
107     *            the requested protocol to create a context for.
108     * @param provider
109     *            the name of the provider that provides the requested protocol.
110     * @return an {@code SSLContext} for the requested protocol.
111     * @throws NoSuchAlgorithmException
112     *             if the specified provider cannot provider the requested
113     *             protocol.
114     * @throws NoSuchProviderException
115     *             if the specified provider does not exits.
116     * @throws NullPointerException
117     *             if {@code protocol} is {@code null} (instead of
118     *             NoSuchAlgorithmException as in 1.4 release)
119     */
120    public static SSLContext getInstance(String protocol, String provider)
121            throws NoSuchAlgorithmException, NoSuchProviderException {
122        if (provider == null) {
123            throw new IllegalArgumentException("Provider is null");
124        }
125        if (provider.length() == 0) {
126            throw new IllegalArgumentException("Provider is empty");
127        }
128        Provider impProvider = Security.getProvider(provider);
129        if (impProvider == null) {
130            throw new NoSuchProviderException(provider);
131        }
132        return getInstance(protocol, impProvider);
133    }
134
135    /**
136     * Creates a new {@code SSLContext} instance for the specified protocol from
137     * the specified provider.
138     *
139     * @param protocol
140     *            the requested protocol to create a context for
141     * @param provider
142     *            the provider that provides the requested protocol.
143     * @return an {@code SSLContext} for the requested protocol.
144     * @throws NoSuchAlgorithmException
145     *             if the specified provider cannot provide the requested
146     *             protocol.
147     * @throws NullPointerException
148     *             if {@code protocol} is {@code null} (instead of
149     *             NoSuchAlgorithmException as in 1.4 release)
150     */
151    public static SSLContext getInstance(String protocol, Provider provider)
152            throws NoSuchAlgorithmException {
153        if (provider == null) {
154            throw new IllegalArgumentException("provider is null");
155        }
156        if (protocol == null) {
157            throw new NullPointerException("protocol == null");
158        }
159        Object spi = ENGINE.getInstance(protocol, provider, null);
160        return new SSLContext((SSLContextSpi) spi, provider, protocol);
161    }
162
163    private final Provider provider;
164
165    private final SSLContextSpi spiImpl;
166
167    private final String protocol;
168
169    /**
170     * Creates a new {@code SSLContext}.
171     *
172     * @param contextSpi
173     *            the implementation delegate.
174     * @param provider
175     *            the provider.
176     * @param protocol
177     *            the protocol name.
178     */
179    protected SSLContext(SSLContextSpi contextSpi, Provider provider, String protocol) {
180        this.provider = provider;
181        this.protocol = protocol;
182        this.spiImpl = contextSpi;
183    }
184
185    /**
186     * Returns the name of the secure socket protocol of this instance.
187     *
188     * @return the name of the secure socket protocol of this instance.
189     */
190    public final String getProtocol() {
191        return protocol;
192    }
193
194    /**
195     * Returns the provider of this {@code SSLContext} instance.
196     *
197     * @return the provider of this {@code SSLContext} instance.
198     */
199    public final Provider getProvider() {
200        return provider;
201    }
202
203    /**
204     * Initializes this {@code SSLContext} instance. All of the arguments are
205     * optional, and the security providers will be searched for the required
206     * implementations of the needed algorithms.
207     *
208     * @param km
209     *            the key sources or {@code null}.
210     * @param tm
211     *            the trust decision sources or {@code null}.
212     * @param sr
213     *            the randomness source or {@code null.}
214     * @throws KeyManagementException
215     *             if initializing this instance fails.
216     */
217    public final void init(KeyManager[] km, TrustManager[] tm, SecureRandom sr)
218            throws KeyManagementException {
219        spiImpl.engineInit(km, tm, sr);
220    }
221
222    /**
223     * Returns a socket factory for this instance.
224     *
225     * @return a socket factory for this instance.
226     */
227    public final SSLSocketFactory getSocketFactory() {
228        return spiImpl.engineGetSocketFactory();
229    }
230
231    /**
232     * Returns a server socket factory for this instance.
233     *
234     * @return a server socket factory for this instance.
235     */
236    public final SSLServerSocketFactory getServerSocketFactory() {
237        return spiImpl.engineGetServerSocketFactory();
238    }
239
240    /**
241     * Creates an {@code SSLEngine} instance from this context.
242     *
243     * @return an {@code SSLEngine} instance from this context.
244     * @throws UnsupportedOperationException
245     *             if the provider does not support the operation.
246     */
247    public final SSLEngine createSSLEngine() {
248        return spiImpl.engineCreateSSLEngine();
249    }
250
251    /**
252     * Creates an {@code SSLEngine} instance from this context with the
253     * specified hostname and port.
254     *
255     * @param peerHost
256     *            the name of the host
257     * @param peerPort
258     *            the port
259     * @return an {@code SSLEngine} instance from this context.
260     * @throws UnsupportedOperationException
261     *             if the provider does not support the operation.
262     */
263    public final SSLEngine createSSLEngine(String peerHost, int peerPort) {
264        return spiImpl.engineCreateSSLEngine(peerHost, peerPort);
265    }
266
267    /**
268     * Returns the SSL session context that encapsulates the set of SSL sessions
269     * that can be used for handshake of server-side SSL sockets.
270     *
271     * @return the SSL server session context for this context or {@code null}
272     *         if the underlying provider does not provide an implementation of
273     *         the {@code SSLSessionContext} interface.
274     */
275    public final SSLSessionContext getServerSessionContext() {
276        return spiImpl.engineGetServerSessionContext();
277    }
278
279    /**
280     * Returns the SSL session context that encapsulates the set of SSL sessions
281     * that can be used for handshake of client-side SSL sockets.
282     *
283     * @return the SSL client session context for this context or {@code null}
284     *         if the underlying provider does not provide an implementation of
285     *         the {@code SSLSessionContext} interface.
286     */
287    public final SSLSessionContext getClientSessionContext() {
288        return spiImpl.engineGetClientSessionContext();
289    }
290
291    /**
292     * Returns the default SSL handshake parameters for SSLSockets
293     * created by this SSLContext.
294     *
295     * @throws UnsupportedOperationException
296     * @since 1.6
297     */
298    public final SSLParameters getDefaultSSLParameters() {
299        return spiImpl.engineGetDefaultSSLParameters();
300    }
301
302    /**
303     * Returns SSL handshake parameters for SSLSockets that includes
304     * all supported cipher suites and protocols.
305     *
306     * @throws UnsupportedOperationException
307     * @since 1.6
308     */
309    public final SSLParameters getSupportedSSLParameters() {
310        return spiImpl.engineGetSupportedSSLParameters();
311    }
312}
313