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