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