001/*
002 * Copyright 2008-2017 UnboundID Corp.
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2008-2017 UnboundID Corp.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.util.ssl;
022
023
024
025import java.io.File;
026import java.io.FileInputStream;
027import java.io.Serializable;
028import java.security.KeyStore;
029import java.security.KeyStoreException;
030import javax.net.ssl.KeyManager;
031import javax.net.ssl.KeyManagerFactory;
032
033import com.unboundid.util.NotMutable;
034import com.unboundid.util.ThreadSafety;
035import com.unboundid.util.ThreadSafetyLevel;
036
037import static com.unboundid.util.Debug.*;
038import static com.unboundid.util.Validator.*;
039import static com.unboundid.util.ssl.SSLMessages.*;
040
041
042
043/**
044 * This class provides an SSL key manager that may be used to retrieve
045 * certificates from a key store file.  By default it will use the default key
046 * store format for the JVM (e.g., "JKS" for Sun-provided Java implementations),
047 * but alternate formats like PKCS12 may be used.
048 */
049@NotMutable()
050@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
051public final class KeyStoreKeyManager
052       extends WrapperKeyManager
053       implements Serializable
054{
055  /**
056   * The serial version UID for this serializable class.
057   */
058  private static final long serialVersionUID = -5202641256733094253L;
059
060
061
062  // The path to the key store file.
063  private final String keyStoreFile;
064
065  // The format to use for the key store file.
066  private final String keyStoreFormat;
067
068
069
070  /**
071   * Creates a new instance of this key store key manager that provides the
072   * ability to retrieve certificates from the specified key store file.  It
073   * will use the default key store format.
074   *
075   * @param  keyStoreFile  The path to the key store file to use.  It must not
076   *                       be {@code null}.
077   * @param  keyStorePIN   The PIN to use to access the contents of the key
078   *                       store.  It may be {@code null} if no PIN is required.
079   *
080   * @throws  KeyStoreException  If a problem occurs while initializing this key
081   *                             manager.
082   */
083  public KeyStoreKeyManager(final File keyStoreFile, final char[] keyStorePIN)
084         throws KeyStoreException
085  {
086    this(keyStoreFile.getAbsolutePath(), keyStorePIN, null, null);
087  }
088
089
090
091  /**
092   * Creates a new instance of this key store key manager that provides the
093   * ability to retrieve certificates from the specified key store file.  It
094   * will use the default key store format.
095   *
096   * @param  keyStoreFile  The path to the key store file to use.  It must not
097   *                       be {@code null}.
098   * @param  keyStorePIN   The PIN to use to access the contents of the key
099   *                       store.  It may be {@code null} if no PIN is required.
100   *
101   * @throws  KeyStoreException  If a problem occurs while initializing this key
102   *                             manager.
103   */
104  public KeyStoreKeyManager(final String keyStoreFile, final char[] keyStorePIN)
105         throws KeyStoreException
106  {
107    this(keyStoreFile, keyStorePIN, null, null);
108  }
109
110
111
112  /**
113   * Creates a new instance of this key store key manager that provides the
114   * ability to retrieve certificates from the specified key store file.
115   *
116   * @param  keyStoreFile      The path to the key store file to use.  It must
117   *                           not be {@code null}.
118   * @param  keyStorePIN       The PIN to use to access the contents of the key
119   *                           store.  It may be {@code null} if no PIN is
120   *                           required.
121   * @param  keyStoreFormat    The format to use for the key store.  It may be
122   *                           {@code null} if the default format should be
123   *                           used.
124   * @param  certificateAlias  The nickname of the certificate that should be
125   *                           selected.  It may be {@code null} if any
126   *                           acceptable certificate found in the keystore may
127   *                           be used.
128   *
129   * @throws  KeyStoreException  If a problem occurs while initializing this key
130   *                             manager.
131   */
132  public KeyStoreKeyManager(final File keyStoreFile, final char[] keyStorePIN,
133                            final String keyStoreFormat,
134                            final String certificateAlias)
135         throws KeyStoreException
136  {
137    this(keyStoreFile.getAbsolutePath(), keyStorePIN, keyStoreFormat,
138         certificateAlias);
139  }
140
141
142
143  /**
144   * Creates a new instance of this key store key manager that provides the
145   * ability to retrieve certificates from the specified key store file.
146   *
147   * @param  keyStoreFile      The path to the key store file to use.  It must
148   *                           not be {@code null}.
149   * @param  keyStorePIN       The PIN to use to access the contents of the key
150   *                           store.  It may be {@code null} if no PIN is
151   *                           required.
152   * @param  keyStoreFormat    The format to use for the key store.  It may be
153   *                           {@code null} if the default format should be
154   *                           used.
155   * @param  certificateAlias  The nickname of the certificate that should be
156   *                           selected.  It may be {@code null} if any
157   *                           acceptable certificate found in the keystore may
158   *                           be used.
159   *
160   * @throws  KeyStoreException  If a problem occurs while initializing this key
161   *                             manager.
162   */
163  public KeyStoreKeyManager(final String keyStoreFile, final char[] keyStorePIN,
164                            final String keyStoreFormat,
165                            final String certificateAlias)
166         throws KeyStoreException
167  {
168    super(getKeyManagers(keyStoreFile, keyStorePIN, keyStoreFormat),
169          certificateAlias);
170
171    this.keyStoreFile     = keyStoreFile;
172
173    if (keyStoreFormat == null)
174    {
175      this.keyStoreFormat = KeyStore.getDefaultType();
176    }
177    else
178    {
179      this.keyStoreFormat = keyStoreFormat;
180    }
181  }
182
183
184
185  /**
186   * Retrieves the set of key managers that will be wrapped by this key manager.
187   *
188   * @param  keyStoreFile      The path to the key store file to use.  It must
189   *                           not be {@code null}.
190   * @param  keyStorePIN       The PIN to use to access the contents of the key
191   *                           store.  It may be {@code null} if no PIN is
192   *                           required.
193   * @param  keyStoreFormat    The format to use for the key store.  It may be
194   *                           {@code null} if the default format should be
195   *                           used.
196   *
197   * @return  The set of key managers that will be wrapped by this key manager.
198   *
199   * @throws  KeyStoreException  If a problem occurs while initializing this key
200   *                             manager.
201   */
202  private static KeyManager[] getKeyManagers(final String keyStoreFile,
203                                             final char[] keyStorePIN,
204                                             final String keyStoreFormat)
205          throws KeyStoreException
206  {
207    ensureNotNull(keyStoreFile);
208
209    String type = keyStoreFormat;
210    if (type == null)
211    {
212      type = KeyStore.getDefaultType();
213    }
214
215    final File f = new File(keyStoreFile);
216    if (! f.exists())
217    {
218      throw new KeyStoreException(ERR_KEYSTORE_NO_SUCH_FILE.get(keyStoreFile));
219    }
220
221    final KeyStore ks = KeyStore.getInstance(type);
222    FileInputStream inputStream = null;
223    try
224    {
225      inputStream = new FileInputStream(f);
226      ks.load(inputStream, keyStorePIN);
227    }
228    catch (Exception e)
229    {
230      debugException(e);
231
232      throw new KeyStoreException(
233           ERR_KEYSTORE_CANNOT_LOAD.get(keyStoreFile, type, String.valueOf(e)),
234           e);
235    }
236    finally
237    {
238      if (inputStream != null)
239      {
240        try
241        {
242          inputStream.close();
243        }
244        catch (Exception e)
245        {
246          debugException(e);
247        }
248      }
249    }
250
251    try
252    {
253      final KeyManagerFactory factory = KeyManagerFactory.getInstance(
254           KeyManagerFactory.getDefaultAlgorithm());
255      factory.init(ks, keyStorePIN);
256      return factory.getKeyManagers();
257    }
258    catch (Exception e)
259    {
260      debugException(e);
261
262      throw new KeyStoreException(ERR_KEYSTORE_CANNOT_GET_KEY_MANAGERS.get(
263           keyStoreFile, keyStoreFormat, String.valueOf(e)), e);
264    }
265  }
266
267
268
269  /**
270   * Retrieves the path to the key store file to use.
271   *
272   * @return  The path to the key store file to use.
273   */
274  public String getKeyStoreFile()
275  {
276    return keyStoreFile;
277  }
278
279
280
281  /**
282   * Retrieves the name of the key store file format.
283   *
284   * @return  The name of the key store file format.
285   */
286  public String getKeyStoreFormat()
287  {
288    return keyStoreFormat;
289  }
290}