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    import com.unboundid.util.NotMutable;
034    import com.unboundid.util.ThreadSafety;
035    import com.unboundid.util.ThreadSafetyLevel;
036    
037    import static com.unboundid.util.Debug.*;
038    import static com.unboundid.util.Validator.*;
039    import 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)
051    public 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    }