001/* KeyManagerFactory.java -- factory for key managers.
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.AccessController;
045import java.security.InvalidAlgorithmParameterException;
046import java.security.KeyStore;
047import java.security.KeyStoreException;
048import java.security.NoSuchAlgorithmException;
049import java.security.NoSuchProviderException;
050import java.security.PrivilegedAction;
051import java.security.Provider;
052import java.security.Security;
053import java.security.UnrecoverableKeyException;
054
055/**
056 * A class that creates key manager implementations based on a
057 * requested algorithm.
058 *
059 * @author Casey Marshall (rsdio@metastatic.org)
060 */
061public class KeyManagerFactory
062{
063
064  // Constants and fields.
065  // ------------------------------------------------------------------
066
067  /** The service name for key manager factories. */
068  private static final String KEY_MANAGER_FACTORY = "KeyManagerFactory";
069
070  /** The system default trust manager algorithm. */
071  private static final String DEFAULT_ALGORITHM = "JessieX509";
072
073  /** The underlying engine. */
074  private final KeyManagerFactorySpi kmfSpi;
075
076  /** The provider of this implementation. */
077  private final Provider provider;
078
079  /** The name of this algorithm. */
080  private final String algorithm;
081
082  // Constructor.
083  // ------------------------------------------------------------------
084
085  /**
086   * Create a new key manager factory.
087   *
088   * @param kmfSpi The underlying engine.
089   * @param provider The engine's provider.
090   * @param algorithm The name of this algorithm.
091   */
092  protected KeyManagerFactory(KeyManagerFactorySpi kmfSpi,
093                              Provider provider, String algorithm)
094  {
095    this.kmfSpi = kmfSpi;
096    this.provider = provider;
097    this.algorithm = algorithm;
098  }
099
100  // Class methods.
101  // ------------------------------------------------------------------
102
103  /**
104   * Get the default algorithm name. This value may be specified at
105   * run-time via the security property
106   * "ssl.KeyManagerFactory.algorithm". If this property is
107   * not specified, this method returns "JessieX509".
108   *
109   * @return The default key manager factory algorithm's name.
110   */
111  public static final String getDefaultAlgorithm()
112  {
113    String alg = null;
114    try
115      {
116        alg = (String) AccessController.doPrivileged(
117          new PrivilegedAction()
118          {
119            public Object run()
120            {
121              return Security.getProperty("ssl.KeyManagerFactory.algorithm");
122            }
123          }
124        );
125      }
126    catch (SecurityException se)
127      {
128      }
129    if (alg == null)
130      alg = DEFAULT_ALGORITHM;
131    return alg;
132  }
133
134  /**
135   * Create an instance of the named key manager factory, from the first
136   * provider that implements it.
137   * 
138   * @param algorithm The type of key manager factory to get.
139   * @return An appropriate implementation of that algoritm.
140   * @throws NoSuchAlgorithmException If no provider implements the requested
141   *           algorithm.
142   * @throws IllegalArgumentException if <code>algorithm</code> is
143   *           <code>null</code> or is an empty string.
144   */
145  public static final KeyManagerFactory getInstance(String algorithm)
146      throws NoSuchAlgorithmException
147  {
148    Provider[] p = Security.getProviders();
149    NoSuchAlgorithmException lastException = null;
150    for (int i = 0; i < p.length; i++)
151      try
152        {
153          return getInstance(algorithm, p[i]);
154        }
155      catch (NoSuchAlgorithmException x)
156        {
157          lastException = x;
158        }
159    if (lastException != null)
160      throw lastException;
161    throw new NoSuchAlgorithmException(algorithm);
162  }
163
164  /**
165   * Create an instance of the named key manager factory, from the named
166   * provider.
167   * 
168   * @param algorithm The type of key manager factory to get.
169   * @param provider The name of the provider to get the implementation from.
170   * @return An appropriate implementation of that algorithm.
171   * @throws NoSuchAlgorithmException If the provider does not implement the
172   *           requested algorithm.
173   * @throws NoSuchProviderException If the named provider does not exist.
174   * @throws IllegalArgumentException if either <code>algorithm</code> or
175   *           <code>provider</code> is <code>null</code>, or if
176   *           <code>algorithm</code> is an empty string.
177   */
178  public static final KeyManagerFactory getInstance(String algorithm,
179                                                    String provider)
180      throws NoSuchAlgorithmException, NoSuchProviderException
181  {
182    if (provider == null)
183      throw new IllegalArgumentException("provider MUST NOT be null");
184    Provider p = Security.getProvider(provider);
185    if (p == null)
186      throw new NoSuchProviderException(provider);
187    return getInstance(algorithm, p);
188  }
189
190  /**
191   * Create an instance of the named key manager factory, from the given
192   * provider.
193   * 
194   * @param algorithm The type of key manager factory to get.
195   * @param provider The provider to get the implementation from.
196   * @return An appropriate implementation of that algorithm.
197   * @throws NoSuchAlgorithmException If the provider does not implement the
198   *           requested algorithm.
199   * @throws IllegalArgumentException if either <code>algorithm</code> or
200   *           <code>provider</code> is <code>null</code>, or if
201   *           <code>algorithm</code> is an empty string.
202   */
203  public static final KeyManagerFactory getInstance(String algorithm,
204                                                    Provider provider)
205      throws NoSuchAlgorithmException
206  {
207    StringBuilder sb = new StringBuilder("KeyManagerFactory algorithm [")
208        .append(algorithm).append("] from provider[")
209        .append(provider).append("] could not be created");
210    Throwable cause;
211    try
212      {
213        Object spi = Engine.getInstance(KEY_MANAGER_FACTORY, algorithm, provider);
214        return new KeyManagerFactory((KeyManagerFactorySpi) spi, provider, algorithm);
215      }
216    catch (InvocationTargetException x)
217      {
218        cause = x.getCause();
219        if (cause instanceof NoSuchAlgorithmException)
220          throw (NoSuchAlgorithmException) cause;
221        if (cause == null)
222          cause = x;
223      }
224    catch (ClassCastException x)
225      {
226        cause = x;
227      }
228    NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString());
229    x.initCause(cause);
230    throw x;
231  }
232
233  /**
234   * Returns the name of this key manager factory algorithm.
235   *
236   * @return The name of this key manager factory algorithm.
237   */
238  public final String getAlgorithm()
239  {
240    return algorithm;
241  }
242
243  /**
244   * Get an array of key managers appropriate for this algorithm, with
245   * the most preferred manager first.
246   *
247   * @return The array of key managers.
248   */
249  public final KeyManager[] getKeyManagers()
250  {
251    return kmfSpi.engineGetKeyManagers();
252  }
253
254  /**
255   * Returns the provider of this implementation.
256   *
257   * @return The provider of this implementation.
258   */
259  public final Provider getProvider()
260  {
261    return provider;
262  }
263
264  /**
265   * Initialize this instance with an implementation-dependent
266   * parameter object.
267   *
268   * @param params The parameters to initialize with.
269   * @throws InvalidAlgorithmParameterException If the specified
270   *   parameters are inappropriate.
271   */
272  public final void init(ManagerFactoryParameters params)
273    throws InvalidAlgorithmParameterException
274  {
275    kmfSpi.engineInit(params);
276  }
277
278  /**
279   * Initialize this instance with a key store and a password for
280   * private key entries.
281   *
282   * @param store The key store to read.
283   * @param passwd The password protecting private keys in the store.
284   * @throws KeyStoreException If an error occurs reading the keys.
285   * @throws NoSuchAlgorithmException If an algorithm (such as a
286   *   certificate algorithm) is not available.
287   * @throws UnrecoverableKeyException If the password is incorrect.
288   */
289  public final void init(KeyStore store, char[] passwd)
290    throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException
291  {
292    kmfSpi.engineInit(store, passwd);
293  }
294}