001/* SSLContext.java -- an SSL protocol context.
002   Copyright (C) 2004 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.net.ssl;
040
041import gnu.java.security.Engine;
042
043import java.lang.reflect.InvocationTargetException;
044import java.security.KeyManagementException;
045import java.security.NoSuchAlgorithmException;
046import java.security.NoSuchProviderException;
047import java.security.Provider;
048import java.security.SecureRandom;
049import java.security.Security;
050
051/**
052 * A "meta-factory" for protocol-specific socket and server socket
053 * factories. This class serves as a clearinghouse for socket
054 * factories and cached session contexts for a particular protocol,
055 * such as SSLv3.
056 *
057 * @author Casey Marshall (rsdio@metastatic.org)
058 */
059public class SSLContext
060{
061  // Constants and fields.
062  // ------------------------------------------------------------------
063
064  /** Service name for SSL contexts. */
065  private static final String SSL_CONTEXT = "SSLContext";
066
067  /** The underlying engine. */
068  private final SSLContextSpi ctxSpi;
069
070  /** The provider of the engine class. */
071  private final Provider provider;
072
073  /** The protocal name. */
074  private final String protocol;
075
076  // Constructor.
077  // ------------------------------------------------------------------
078
079  /**
080   * Create a new SSL context.
081   *
082   * @param ctxSpi The context engine.
083   * @param provider The provider of the implementation.
084   * @param protocol The name of the SSL protocol.
085   */
086  protected SSLContext(SSLContextSpi ctxSpi, Provider provider,
087                       String protocol)
088  {
089    this.ctxSpi = ctxSpi;
090    this.provider = provider;
091    this.protocol = protocol;
092  }
093
094  /**
095   * Get an instance of a context for the specified protocol from the first
096   * provider that implements it.
097   * 
098   * @param protocol The name of the protocol to get a context for.
099   * @return The new context.
100   * @throws NoSuchAlgorithmException If no provider implements the given
101   *           protocol.
102   * @throws IllegalArgumentException if <code>protocol</code> is
103   *           <code>null</code> or is an empty string.
104   */
105  public static final SSLContext getInstance(String protocol)
106      throws NoSuchAlgorithmException
107  {
108    Provider[] p = Security.getProviders();
109    NoSuchAlgorithmException lastException = null;
110    for (int i = 0; i < p.length; i++)
111      try
112        {
113          return getInstance(protocol, p[i]);
114        }
115      catch (NoSuchAlgorithmException x)
116        {
117          lastException = x;
118        }
119    if (lastException != null)
120      throw lastException;
121    throw new NoSuchAlgorithmException(protocol);
122  }
123
124  /**
125   * Get an instance of a context for the specified protocol from the named
126   * provider.
127   * 
128   * @param protocol The name of the protocol to get a context for.
129   * @param provider The name of the provider to get the implementation from.
130   * @return The new context.
131   * @throws NoSuchAlgorithmException If the provider does not implement the
132   *           given protocol.
133   * @throws NoSuchProviderException If the named provider does not exist.
134   * @throws IllegalArgumentException if either <code>protocol</code> or
135   *           <code>provider</code> is <code>null</code>, or if
136   *           <code>protocol</code> is an empty string.
137   */
138  public static final SSLContext getInstance(String protocol, String provider)
139      throws NoSuchAlgorithmException, NoSuchProviderException
140  {
141    if (provider == null)
142      throw new IllegalArgumentException("provider MUST NOT be null");
143    Provider p = Security.getProvider(provider);
144    if (p == null)
145      throw new NoSuchProviderException(provider);
146    return getInstance(protocol, p);
147  }
148
149  /**
150   * Get an instance of a context for the specified protocol from the specified
151   * provider.
152   * 
153   * @param protocol The name of the protocol to get a context for.
154   * @param provider The name of the provider to get the implementation from.
155   * @return The new context.
156   * @throws NoSuchAlgorithmException If the provider does not implement the
157   *           given protocol.
158   * @throws IllegalArgumentException if either <code>protocol</code> or
159   *           <code>provider</code> is <code>null</code>, or if
160   *           <code>protocol</code> is an empty string.
161   */
162  public static final SSLContext getInstance(String protocol, Provider provider)
163      throws NoSuchAlgorithmException
164  {
165    StringBuilder sb = new StringBuilder("SSLContext for protocol [")
166        .append(protocol).append("] from provider[")
167        .append(provider).append("] could not be created");
168    Throwable cause;
169    try
170      {
171        Object spi = Engine.getInstance(SSL_CONTEXT, protocol, provider);
172        return new SSLContext((SSLContextSpi) spi, provider, protocol);
173      }
174    catch (InvocationTargetException x)
175      {
176        cause = x.getCause();
177        if (cause instanceof NoSuchAlgorithmException)
178          throw (NoSuchAlgorithmException) cause;
179        if (cause == null)
180          cause = x;
181      }
182    catch (ClassCastException x)
183      {
184        cause = x;
185      }
186    NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
187    x.initCause(cause);
188    throw x;
189  }
190
191  /**
192   * Creates a new {@link SSLEngine} for this context.
193   *
194   * @return The new SSLEngine.
195   * @since 1.5
196   */
197  public final SSLEngine createSSLEngine ()
198  {
199    return ctxSpi.engineCreateSSLEngine ();
200  }
201
202  /**
203   * Creates a new {@link SSLEngine} for this context, with a given
204   * host name and port number.
205   *
206   * @param host The local host name.
207   * @param port The local port number.
208   * @return The new SSLEngine.
209   * @since 1.5
210   */
211  public final SSLEngine createSSLEngine (final String host, final int port)
212  {
213    return ctxSpi.engineCreateSSLEngine (host, port);
214  }
215
216  /**
217   * Returns the set of SSL contexts available for client connections.
218   *
219   * @return The set of SSL contexts available for client connections.
220   */
221  public final SSLSessionContext getClientSessionContext()
222  {
223    return ctxSpi.engineGetClientSessionContext();
224  }
225
226  /**
227   * Returns the protocol name of this context.
228   *
229   * @return The protocol name of this context.
230   */
231  public final String getProtocol()
232  {
233    return protocol;
234  }
235
236  /**
237   * Returns the provider of this implementation.
238   *
239   * @return The provider of this implementation.
240   */
241  public final Provider getProvider()
242  {
243    return provider;
244  }
245
246  /**
247   * Returns the set of SSL contexts available for server connections.
248   *
249   * @return The set of SSL contexts available for server connections.
250   */
251  public final SSLSessionContext getServerSessionContext()
252  {
253    return ctxSpi.engineGetServerSessionContext();
254  }
255
256  /**
257   * Returns the factory for server SSL sockets.
258   *
259   * @return The factory for server SSL sockets.
260   */
261  public final SSLServerSocketFactory getServerSocketFactory()
262  {
263    return ctxSpi.engineGetServerSocketFactory();
264  }
265
266  /**
267   * Returns the factory for client SSL sockets.
268   *
269   * @return The factory for client SSL sockets.
270   */
271  public final SSLSocketFactory getSocketFactory()
272  {
273    return ctxSpi.engineGetSocketFactory();
274  }
275
276  /**
277   * Initializes this context and prepares it for producing socket
278   * factories. All of the parameters are optional; default values are
279   * used if left unspecified.
280   *
281   * @param keyManagers The set of key managers to use.
282   * @param trustManagers The set of trust managers to use.
283   * @param random A source of random bits to use.
284   * @throws KeyManagementException If initialization fails.
285   */
286  public final void init(KeyManager[] keyManagers,
287                         TrustManager[] trustManagers,
288                         SecureRandom random)
289    throws KeyManagementException
290  {
291    ctxSpi.engineInit(keyManagers, trustManagers, random);
292  }
293}