KeyStore.java revision e3a187163504f00c98bd75cbd8bcbdde123ae2cd
1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.security;
19
20import java.io.File;
21import java.io.FileInputStream;
22import java.io.IOException;
23import java.io.InputStream;
24import java.io.OutputStream;
25import java.security.cert.Certificate;
26import java.security.cert.CertificateException;
27import java.security.cert.X509Certificate;
28import java.util.Arrays;
29import java.util.Date;
30import java.util.Enumeration;
31
32import javax.crypto.SecretKey;
33import javax.security.auth.DestroyFailedException;
34import javax.security.auth.Destroyable;
35import javax.security.auth.callback.CallbackHandler;
36
37import org.apache.harmony.security.fortress.Engine;
38
39/**
40 * {@code KeyStore} is responsible for maintaining cryptographic keys and their
41 * owners.
42 * <p>
43 * The type of the system key store can be changed by setting the {@code
44 * 'keystore.type'} property in the file named {@code
45 * JAVA_HOME/lib/security/java.security}.
46 *
47 * @see Certificate
48 * @see PrivateKey
49 */
50public class KeyStore {
51
52    // Store KeyStore SERVICE name
53    private static final String SERVICE = "KeyStore";
54
55    // Used to access common engine functionality
56    private static Engine engine = new Engine(SERVICE);
57
58    //  Store KeyStore property name
59    private static final String PROPERTYNAME = "keystore.type";
60
61    //  Store default KeyStore type
62    private static final String DEFAULT_KEYSTORE_TYPE = "jks";
63
64    // Store KeyStore state (initialized or not)
65    private boolean isInit;
66
67    // Store used KeyStoreSpi
68    private final KeyStoreSpi implSpi;
69
70    // Store used provider
71    private final Provider provider;
72
73    // Store used type
74    private final String type;
75
76    /**
77     * Constructs a new instance of {@code KeyStore} with the given arguments.
78     *
79     * @param keyStoreSpi
80     *            the concrete key store.
81     * @param provider
82     *            the provider.
83     * @param type
84     *            the type of the {@code KeyStore} to be constructed.
85     */
86    protected KeyStore(KeyStoreSpi keyStoreSpi, Provider provider, String type) {
87        this.type = type;
88        this.provider = provider;
89        this.implSpi = keyStoreSpi;
90        isInit = false;
91    }
92
93    /**
94     * Throws the standard "keystore not initialized" exception.
95     */
96    private static void throwNotInitialized() throws KeyStoreException {
97        throw new KeyStoreException("KeyStore was not initialized");
98    }
99
100    /**
101     * Returns a new instance of {@code KeyStore} with the specified type.
102     *
103     * @param type
104     *            the type of the returned {@code KeyStore}.
105     * @return a new instance of {@code KeyStore} with the specified type.
106     * @throws KeyStoreException
107     *             if an error occurred during the creation of the new {@code
108     *             KeyStore}.
109     * @throws NullPointerException if {@code type == null}
110     * @see #getDefaultType
111     */
112    public static KeyStore getInstance(String type) throws KeyStoreException {
113        if (type == null) {
114            throw new NullPointerException();
115        }
116        synchronized (engine) {
117            try {
118                engine.getInstance(type, null);
119                return new KeyStore((KeyStoreSpi) engine.spi, engine.provider, type);
120            } catch (NoSuchAlgorithmException e) {
121                throw new KeyStoreException(e.getMessage());
122            }
123        }
124    }
125
126    /**
127     * Returns a new instance of {@code KeyStore} from the specified provider
128     * with the given type.
129     *
130     * @param type
131     *            the type of the returned {@code KeyStore}.
132     * @param provider
133     *            name of the provider of the {@code KeyStore}.
134     * @return a new instance of {@code KeyStore} from the specified provider
135     *         with the given type.
136     * @throws KeyStoreException
137     *             if an error occurred during the creation of the new {@code
138     *             KeyStore}.
139     * @throws NoSuchProviderException
140     *             if the specified provider is not available.
141     * @throws IllegalArgumentException if {@code provider == null || provider.isEmpty()}
142     * @throws NullPointerException
143     *             if {@code type} is {@code null} (instead of
144     *             NoSuchAlgorithmException) as in 1.4 release
145     * @see #getDefaultType
146     */
147    public static KeyStore getInstance(String type, String provider)
148            throws KeyStoreException, NoSuchProviderException {
149        if (provider == null || provider.isEmpty()) {
150            throw new IllegalArgumentException();
151        }
152        Provider impProvider = Security.getProvider(provider);
153        if (impProvider == null) {
154            throw new NoSuchProviderException(provider);
155        }
156        try {
157            return getInstance(type, impProvider);
158        } catch (Exception e) {
159            throw new KeyStoreException(e.getMessage(), e);
160        }
161    }
162
163    /**
164     * Returns a new instance of {@code KeyStore} from the specified provider
165     * with the given type.
166     *
167     * @param type
168     *            the type of the returned {@code KeyStore}.
169     * @param provider
170     *            the provider of the {@code KeyStore}.
171     * @return a new instance of {@code KeyStore} from the specified provider
172     *         with the given type.
173     * @throws KeyStoreException
174     *             if an error occurred during the creation of the new {@code
175     *             KeyStore}.
176     * @throws IllegalArgumentException
177     *             if {@code provider} is {@code null} or the empty string.
178     * @throws NullPointerException if {@code type == null} (instead of
179     *             NoSuchAlgorithmException) as in 1.4 release
180     * @see #getDefaultType
181     */
182    public static KeyStore getInstance(String type, Provider provider)
183            throws KeyStoreException {
184        // check parameters
185        if (provider == null) {
186            throw new IllegalArgumentException();
187        }
188        if (type == null) {
189            throw new NullPointerException();
190        }
191        // return KeyStore instance
192        synchronized (engine) {
193            try {
194                engine.getInstance(type, provider, null);
195                return new KeyStore((KeyStoreSpi) engine.spi, provider, type);
196            } catch (Exception e) {
197            // override exception
198                throw new KeyStoreException(e.getMessage());
199            }
200        }
201    }
202
203    /**
204     * Returns the default type for {@code KeyStore} instances.
205     * <p>
206     * The default is specified in the {@code 'keystore.type'} property in the
207     * file named {@code JAVA_HOME/lib/security/java.security}. If this property
208     * is not set, {@code "jks"} will be used.
209     *
210     * @return the default type for {@code KeyStore} instances
211     */
212    public static final String getDefaultType() {
213        String dt = AccessController.doPrivileged(
214                new PrivilegedAction<String>() {
215                    public String run() {
216                        return Security.getProperty(PROPERTYNAME);
217                    }
218                }
219            );
220        return (dt == null ? DEFAULT_KEYSTORE_TYPE : dt);
221    }
222
223    /**
224     * Returns the provider associated with this {@code KeyStore}.
225     *
226     * @return the provider associated with this {@code KeyStore}.
227     */
228    public final Provider getProvider() {
229        return provider;
230    }
231
232    /**
233     * Returns the type of this {@code KeyStore}.
234     *
235     * @return the type of this {@code KeyStore}.
236     */
237    public final String getType() {
238        return type;
239    }
240
241    /**
242     * Returns the key with the given alias, using the password to recover the
243     * key from the store.
244     *
245     * @param alias
246     *            the alias for the entry.
247     * @param password
248     *            the password used to recover the key.
249     * @return the key with the specified alias, or {@code null} if the
250     *         specified alias is not bound to an entry.
251     * @throws KeyStoreException
252     *             if this {@code KeyStore} is not initialized.
253     * @throws NoSuchAlgorithmException
254     *             if the algorithm for recovering the key is not available.
255     * @throws UnrecoverableKeyException
256     *             if the key can not be recovered.
257     */
258    public final Key getKey(String alias, char[] password)
259            throws KeyStoreException, NoSuchAlgorithmException,
260            UnrecoverableKeyException {
261        if (!isInit) {
262            // BEGIN android-changed
263            throwNotInitialized();
264            // END android-changed
265        }
266        return implSpi.engineGetKey(alias, password);
267    }
268
269    /**
270     * Returns the certificate chain for the entry with the given alias.
271     *
272     * @param alias
273     *            the alias for the entry.
274     * @return the certificate chain for the entry with the given alias, or
275     *         {@code null} if the specified alias is not bound to an entry.
276     * @throws KeyStoreException
277     *             if this {@code KeyStore} is not initialized.
278     */
279    public final Certificate[] getCertificateChain(String alias)
280            throws KeyStoreException {
281        if (!isInit) {
282            // BEGIN android-changed
283            throwNotInitialized();
284            // END android-changed
285        }
286        return implSpi.engineGetCertificateChain(alias);
287    }
288
289    /**
290     * Returns the trusted certificate for the entry with the given alias.
291     *
292     * @param alias
293     *            the alias for the entry.
294     * @return the trusted certificate for the entry with the given alias, or
295     *         {@code null} if the specified alias is not bound to an entry.
296     * @throws KeyStoreException
297     *             if this {@code KeyStore} is not initialized.
298     */
299    public final Certificate getCertificate(String alias)
300            throws KeyStoreException {
301        if (!isInit) {
302            // BEGIN android-changed
303            throwNotInitialized();
304            // END android-changed
305        }
306        return implSpi.engineGetCertificate(alias);
307    }
308
309    /**
310     * Returns the creation date of the entry with the given alias.
311     *
312     * @param alias
313     *            the alias for the entry.
314     * @return the creation date, or {@code null} if the specified alias is not
315     *         bound to an entry.
316     * @throws KeyStoreException
317     *             if this {@code KeyStore} is not initialized.
318     */
319    public final Date getCreationDate(String alias) throws KeyStoreException {
320        if (!isInit) {
321            // BEGIN android-changed
322            throwNotInitialized();
323            // END android-changed
324        }
325        return implSpi.engineGetCreationDate(alias);
326    }
327
328    /**
329     * Associates the given alias with the key, password and certificate chain.
330     * <p>
331     * If the specified alias already exists, it will be reassigned.
332     *
333     * @param alias
334     *            the alias for the key.
335     * @param key
336     *            the key.
337     * @param password
338     *            the password.
339     * @param chain
340     *            the certificate chain.
341     * @throws KeyStoreException
342     *             if this {@code KeyStore} is not initialized.
343     * @throws IllegalArgumentException
344     *             if {@code key} is a {@code PrivateKey} and {@code chain} does
345     *             not contain any certificates.
346     * @throws NullPointerException
347     *             if {@code alias} is {@code null}.
348     */
349    public final void setKeyEntry(String alias, Key key, char[] password,
350            Certificate[] chain) throws KeyStoreException {
351        if (!isInit) {
352            // BEGIN android-changed
353            throwNotInitialized();
354            // END android-changed
355        }
356
357        // Certificate chain is required for PrivateKey
358        if (null != key && key instanceof PrivateKey && (chain == null || chain.length == 0)) {
359            throw new IllegalArgumentException("Certificate chain is not defined for Private key");
360        }
361        implSpi.engineSetKeyEntry(alias, key, password, chain);
362    }
363
364    /**
365     * Associates the given alias with a key and a certificate chain.
366     * <p>
367     * If the specified alias already exists, it will be reassigned.
368     * <p>
369     * If this {@code KeyStore} is of type {@code "jks"}, {@code key} must be
370     * encoded conform to the PKS#8 standard as an
371     * {@link javax.crypto.EncryptedPrivateKeyInfo}.
372     *
373     * @param alias
374     *            the alias for the key.
375     * @param key
376     *            the key in an encoded format.
377     * @param chain
378     *            the certificate chain.
379     * @throws KeyStoreException
380     *             if this {@code KeyStore} is not initialized or if {@code key}
381     *             is null.
382     * @throws IllegalArgumentException
383     *             if {@code key} is a {@code PrivateKey} and {@code chain}
384     *             does.
385     * @throws NullPointerException
386     *             if {@code alias} is {@code null}.
387     */
388    public final void setKeyEntry(String alias, byte[] key, Certificate[] chain)
389            throws KeyStoreException {
390        if (!isInit) {
391            // BEGIN android-changed
392            throwNotInitialized();
393            // END android-changed
394        }
395        implSpi.engineSetKeyEntry(alias, key, chain);
396    }
397
398    /**
399     * Associates the given alias with a certificate.
400     * <p>
401     * If the specified alias already exists, it will be reassigned.
402     *
403     * @param alias
404     *            the alias for the certificate.
405     * @param cert
406     *            the certificate.
407     * @throws KeyStoreException
408     *             if this {@code KeyStore} is not initialized, or an existing
409     *             alias is not associated to an entry containing a trusted
410     *             certificate, or this method fails for any other reason.
411     * @throws NullPointerException
412     *             if {@code alias} is {@code null}.
413     */
414    public final void setCertificateEntry(String alias, Certificate cert)
415            throws KeyStoreException {
416        if (!isInit) {
417            // BEGIN android-changed
418            throwNotInitialized();
419            // END android-changed
420        }
421        implSpi.engineSetCertificateEntry(alias, cert);
422    }
423
424    /**
425     * Deletes the entry identified with the given alias from this {@code
426     * KeyStore}.
427     *
428     * @param alias
429     *            the alias for the entry.
430     * @throws KeyStoreException
431     *             if this {@code KeyStore} is not initialized, or if the entry
432     *             can not be deleted.
433     */
434    public final void deleteEntry(String alias) throws KeyStoreException {
435        if (!isInit) {
436            // BEGIN android-changed
437            throwNotInitialized();
438            // END android-changed
439        }
440        implSpi.engineDeleteEntry(alias);
441    }
442
443    /**
444     * Returns an {@code Enumeration} over all alias names stored in this
445     * {@code KeyStore}.
446     *
447     * @return an {@code Enumeration} over all alias names stored in this
448     *         {@code KeyStore}.
449     * @throws KeyStoreException
450     *             if this {@code KeyStore} is not initialized.
451     */
452    public final Enumeration<String> aliases() throws KeyStoreException {
453        if (!isInit) {
454            // BEGIN android-changed
455            throwNotInitialized();
456            // END android-changed
457        }
458        return implSpi.engineAliases();
459    }
460
461    /**
462     * Indicates whether the given alias is present in this {@code KeyStore}.
463     *
464     * @param alias
465     *            the alias of an entry.
466     * @return {@code true} if the alias exists, {@code false} otherwise.
467     * @throws KeyStoreException
468     *             if this {@code KeyStore} is not initialized.
469     */
470    public final boolean containsAlias(String alias) throws KeyStoreException {
471        if (!isInit) {
472            // BEGIN android-changed
473            throwNotInitialized();
474            // END android-changed
475        }
476        return implSpi.engineContainsAlias(alias);
477    }
478
479    /**
480     * Returns the number of entries stored in this {@code KeyStore}.
481     *
482     * @return the number of entries stored in this {@code KeyStore}.
483     * @throws KeyStoreException
484     *             if this {@code KeyStore} is not initialized.
485     */
486    public final int size() throws KeyStoreException {
487        if (!isInit) {
488            // BEGIN android-changed
489            throwNotInitialized();
490            // END android-changed
491        }
492        return implSpi.engineSize();
493    }
494
495    /**
496     * Indicates whether the specified alias is associated with either a
497     * {@link PrivateKeyEntry} or a {@link SecretKeyEntry}.
498     *
499     * @param alias
500     *            the alias of an entry.
501     * @return {@code true} if the given alias is associated with a key entry.
502     * @throws KeyStoreException
503     *             if this {@code KeyStore} is not initialized.
504     */
505    public final boolean isKeyEntry(String alias) throws KeyStoreException {
506        if (!isInit) {
507            // BEGIN android-changed
508            throwNotInitialized();
509            // END android-changed
510        }
511        return implSpi.engineIsKeyEntry(alias);
512    }
513
514    /**
515     * Indicates whether the specified alias is associated with a
516     * {@link TrustedCertificateEntry}.
517     *
518     * @param alias
519     *            the alias of an entry.
520     * @return {@code true} if the given alias is associated with a certificate
521     *         entry.
522     * @throws KeyStoreException
523     *             if this {@code KeyStore} is not initialized.
524     */
525    public final boolean isCertificateEntry(String alias)
526            throws KeyStoreException {
527        if (!isInit) {
528            // BEGIN android-changed
529            throwNotInitialized();
530            // END android-changed
531        }
532        return implSpi.engineIsCertificateEntry(alias);
533    }
534
535    /**
536     * Returns the alias associated with the first entry whose certificate
537     * matches the specified certificate.
538     *
539     * @param cert
540     *            the certificate to find the associated entry's alias for.
541     * @return the alias or {@code null} if no entry with the specified
542     *         certificate can be found.
543     * @throws KeyStoreException
544     *             if this {@code KeyStore} is not initialized.
545     */
546    public final String getCertificateAlias(Certificate cert)
547            throws KeyStoreException {
548        if (!isInit) {
549            // BEGIN android-changed
550            throwNotInitialized();
551            // END android-changed
552        }
553        return implSpi.engineGetCertificateAlias(cert);
554    }
555
556    /**
557     * Writes this {@code KeyStore} to the specified {@code OutputStream}. The
558     * data written to the {@code OutputStream} is protected by the specified
559     * password.
560     *
561     * @param stream
562     *            the {@code OutputStream} to write the store's data to.
563     * @param password
564     *            the password to protect the data.
565     * @throws KeyStoreException
566     *             if this {@code KeyStore} is not initialized.
567     * @throws IOException
568     *             if a problem occurred while writing to the stream.
569     * @throws NoSuchAlgorithmException
570     *             if the required algorithm is not available.
571     * @throws CertificateException
572     *             if an exception occurred while storing the certificates of
573     *             this {@code KeyStore}.
574     */
575    public final void store(OutputStream stream, char[] password)
576            throws KeyStoreException, IOException, NoSuchAlgorithmException,
577            CertificateException {
578        if (!isInit) {
579            // BEGIN android-changed
580            throwNotInitialized();
581            // END android-changed
582        }
583
584        //Just delegate stream and password to implSpi
585        implSpi.engineStore(stream, password);
586    }
587
588    /**
589     * Stores this {@code KeyStore} using the specified {@code
590     * LoadStoreParameter}.
591     *
592     * @param param
593     *            the {@code LoadStoreParameter} that specifies how to store
594     *            this {@code KeyStore}, maybe {@code null}.
595     * @throws KeyStoreException
596     *             if this {@code KeyStore} is not initialized.
597     * @throws IOException
598     *             if a problem occurred while writing to the stream.
599     * @throws NoSuchAlgorithmException
600     *             if the required algorithm is not available.
601     * @throws CertificateException
602     *             if an exception occurred while storing the certificates of
603     *             this {@code KeyStore}.
604     * @throws IllegalArgumentException
605     *             if the given {@link LoadStoreParameter} is not recognized.
606     */
607    public final void store(LoadStoreParameter param) throws KeyStoreException,
608            IOException, NoSuchAlgorithmException, CertificateException {
609        if (!isInit) {
610            // BEGIN android-changed
611            throwNotInitialized();
612            // END android-changed
613        }
614        implSpi.engineStore(param);
615    }
616
617    /**
618     * Initializes this {@code KeyStore} from the provided {@code InputStream}.
619     * Pass {@code null} as the {@code stream} argument to initialize an empty
620     * {@code KeyStore} or to initialize a {@code KeyStore} which does not rely
621     * on an {@code InputStream}. This {@code KeyStore} utilizes the given
622     * password to verify the stored data.
623     *
624     * @param stream
625     *            the {@code InputStream} to load this {@code KeyStore}'s data
626     *            from or {@code null}.
627     * @param password
628     *            the password to verify the stored data, maybe {@code null}.
629     * @throws IOException
630     *             if a problem occurred while reading from the stream.
631     * @throws NoSuchAlgorithmException
632     *             if the required algorithm is not available.
633     * @throws CertificateException
634     *             if an exception occurred while loading the certificates of
635     *             this {@code KeyStore}.
636     */
637    public final void load(InputStream stream, char[] password)
638            throws IOException, NoSuchAlgorithmException, CertificateException {
639        implSpi.engineLoad(stream, password);
640        isInit = true;
641    }
642
643    /**
644     * Loads this {@code KeyStore} using the specified {@code
645     * LoadStoreParameter}.
646     *
647     * @param param
648     *            the {@code LoadStoreParameter} that specifies how to load this
649     *            {@code KeyStore}, maybe {@code null}.
650     * @throws IOException
651     *             if a problem occurred while reading from the stream.
652     * @throws NoSuchAlgorithmException
653     *             if the required algorithm is not available.
654     * @throws CertificateException
655     *             if an exception occurred while loading the certificates of
656     *             this {@code KeyStore}.
657     * @throws IllegalArgumentException
658     *             if the given {@link LoadStoreParameter} is not recognized.
659     */
660    public final void load(LoadStoreParameter param) throws IOException,
661            NoSuchAlgorithmException, CertificateException {
662        implSpi.engineLoad(param);
663        isInit = true;
664    }
665
666    /**
667     * Returns the {@code Entry} with the given alias, using the specified
668     * {@code ProtectionParameter}.
669     *
670     * @param alias
671     *            the alias of the requested entry.
672     * @param param
673     *            the {@code ProtectionParameter} used to protect the requested
674     *            entry, maybe {@code null}.
675     * @return he {@code Entry} with the given alias, using the specified
676     *         {@code ProtectionParameter}.
677     * @throws NoSuchAlgorithmException
678     *             if the required algorithm is not available.
679     * @throws UnrecoverableEntryException
680     *             if the entry can not be recovered.
681     * @throws KeyStoreException
682     *             if this {@code KeyStore} is not initialized.
683     * @throws NullPointerException
684     *             if {@code alias} is {@code null}.
685     */
686    public final Entry getEntry(String alias, ProtectionParameter param)
687            throws NoSuchAlgorithmException, UnrecoverableEntryException,
688            KeyStoreException {
689        if (alias == null) {
690            throw new NullPointerException("alias == null");
691        }
692        if (!isInit) {
693            // BEGIN android-changed
694            throwNotInitialized();
695            // END android-changed
696        }
697        return implSpi.engineGetEntry(alias, param);
698    }
699
700    /**
701     * Stores the given {@code Entry} in this {@code KeyStore} and associates
702     * the entry with the given {@code alias}. The entry is protected by the
703     * specified {@code ProtectionParameter}.
704     * <p>
705     * If the specified alias already exists, it will be reassigned.
706     *
707     * @param alias
708     *            the alias for the entry.
709     * @param entry
710     *            the entry to store.
711     * @param param
712     *            the {@code ProtectionParameter} to protect the entry.
713     * @throws KeyStoreException
714     *             if this {@code KeyStore} is not initialized.
715     * @throws NullPointerException
716     *             if {@code alias} is {@code null} or {@code entry} is {@code
717     *             null}.
718     */
719    public final void setEntry(String alias, Entry entry,
720            ProtectionParameter param) throws KeyStoreException {
721        if (!isInit) {
722            // BEGIN android-changed
723            throwNotInitialized();
724            // END android-changed
725        }
726        if (alias == null) {
727            throw new NullPointerException("alias == null");
728        }
729        if (entry == null) {
730            throw new NullPointerException("entry == null");
731        }
732        implSpi.engineSetEntry(alias, entry, param);
733    }
734
735    /**
736     * Indicates whether the entry for the given alias is assignable to the
737     * provided {@code Class}.
738     *
739     * @param alias
740     *            the alias for the entry.
741     * @param entryClass
742     *            the type of the entry.
743     * @return {@code true} if the {@code Entry} for the alias is assignable to
744     *         the specified {@code entryClass}.
745     * @throws KeyStoreException
746     *             if this {@code KeyStore} is not initialized.
747     */
748    public final boolean entryInstanceOf(String alias,
749            Class<? extends KeyStore.Entry> entryClass)
750            throws KeyStoreException {
751        if (alias == null) {
752            throw new NullPointerException("alias == null");
753        }
754        if (entryClass == null) {
755            throw new NullPointerException("entryClass == null");
756        }
757
758        if (!isInit) {
759            // BEGIN android-changed
760            throwNotInitialized();
761            // END android-changed
762        }
763        return implSpi.engineEntryInstanceOf(alias, entryClass);
764    }
765
766    /**
767     * {@code Builder} is used to construct new instances of {@code KeyStore}.
768     */
769    public abstract static class Builder {
770        /**
771         * Constructs a new instance of {@code Builder}.
772         */
773        protected Builder() {
774        }
775
776        /**
777         * Returns the {@code KeyStore} created by this {@code Builder}.
778         *
779         * @return the {@code KeyStore} created by this {@code Builder}.
780         * @throws KeyStoreException
781         *             if an error occurred during construction.
782         */
783        public abstract KeyStore getKeyStore() throws KeyStoreException;
784
785        /**
786         * Returns the {@code ProtectionParameter} to be used when a {@code
787         * Entry} with the specified alias is requested. Before this method is
788         * invoked, {@link #getKeyStore()} must be called.
789         *
790         * @param alias
791         *            the alias for the entry.
792         * @return the {@code ProtectionParameter} to be used when a {@code
793         *         Entry} with the specified alias is requested.
794         * @throws KeyStoreException
795         *             if an error occurred during the lookup for the protection
796         *             parameter.
797         * @throws IllegalStateException
798         *             if {@link #getKeyStore()} is not called prior the
799         *             invocation of this method.
800         * @throws NullPointerException
801         *             if {@code alias} is {@code null}.
802         */
803        public abstract ProtectionParameter getProtectionParameter(String alias)
804                throws KeyStoreException;
805
806        /**
807         * Returns a new {@code Builder} that holds the given {@code KeyStore}
808         * and the given {@code ProtectionParameter}.
809         *
810         * @param keyStore
811         *            the {@code KeyStore} to be held.
812         * @param protectionParameter
813         *            the {@code ProtectionParameter} to be held.
814         * @return a new instance of {@code Builder} that holds the specified
815         *         {@code KeyStore} and the specified {@code
816         *         ProtectionParameter}.
817         * @throws NullPointerException
818         *             if {@code keyStore} or {@code protectionParameter} is
819         *             {@code null}.
820         * @throws IllegalArgumentException
821         *             if the given {@code KeyStore} is not initialized.
822         */
823        public static Builder newInstance(KeyStore keyStore,
824                ProtectionParameter protectionParameter) {
825            if (keyStore == null) {
826                throw new NullPointerException("keyStore == null");
827            }
828            if (protectionParameter == null) {
829                throw new NullPointerException("protectionParameter == null");
830            }
831            if (!keyStore.isInit) {
832                throw new IllegalArgumentException("KeyStore was not initialized");
833            }
834            return new BuilderImpl(keyStore, protectionParameter,
835                    null, null, null, null);
836        }
837
838        /**
839         * Returns a new {@code Builder} that creates a new {@code KeyStore}
840         * based on the provided arguments.
841         * <p>
842         * If {@code provider} is {@code null}, all installed providers are
843         * searched, otherwise the key store from the specified provider is
844         * used.
845         *
846         * @param type
847         *            the type of the {@code KeyStore} to be constructed.
848         * @param provider
849         *            the provider of the {@code KeyStore} to be constructed,
850         *            maybe {@code null}.
851         * @param file
852         *            the {@code File} that contains the data for the {@code
853         *            KeyStore}.
854         * @param protectionParameter
855         *            the {@code ProtectionParameter} used to protect the stored
856         *            keys.
857         * @return a new {@code Builder} that creates a new {@code KeyStore}
858         *         based on the provided arguments.
859         * @throws NullPointerException
860         *             if {@code type, protectionParameter} or {@code file} is
861         *             {@code null}.
862         * @throws IllegalArgumentException
863         *             {@code protectionParameter} not an instance of either
864         *             {@code PasswordProtection} or {@code
865         *             CallbackHandlerProtection}, {@code file} is not a file or
866         *             does not exist at all.
867         */
868        public static Builder newInstance(String type, Provider provider,
869                File file, ProtectionParameter protectionParameter) {
870            // check null parameters
871            if (type == null) {
872                throw new NullPointerException("type == null");
873            }
874            if (protectionParameter == null) {
875                throw new NullPointerException("protectionParameter == null");
876            }
877            if (file == null) {
878                throw new NullPointerException("file == null");
879            }
880            // protection parameter should be PasswordProtection or
881            // CallbackHandlerProtection
882            if (!(protectionParameter instanceof PasswordProtection)
883                    && !(protectionParameter instanceof CallbackHandlerProtection)) {
884                throw new IllegalArgumentException("protectionParameter is neither PasswordProtection nor CallbackHandlerProtection instance");
885            }
886            // check file parameter
887            if (!file.exists()) {
888                throw new IllegalArgumentException("File does not exist: " + file.getName());
889            }
890            if (!file.isFile()) {
891                throw new IllegalArgumentException("Not a regular file: " + file.getName());
892            }
893            // create new instance
894            return new BuilderImpl(null, protectionParameter, file,
895                    type, provider, AccessController.getContext());
896        }
897
898        /**
899         * Returns a new {@code Builder} that creates a new {@code KeyStore}
900         * based on the provided arguments.
901         * <p>
902         * If {@code provider} is {@code null}, all installed providers are
903         * searched, otherwise the key store from the specified provider is
904         * used.
905         *
906         * @param type
907         *            the type of the {@code KeyStore} to be constructed.
908         * @param provider
909         *            the provider of the {@code KeyStore} to be constructed,
910         *            maybe {@code null}.
911         * @param protectionParameter
912         *            the {@code ProtectionParameter} used to protect the stored
913         *            keys.
914         * @return a new {@code Builder} that creates a new {@code KeyStore}
915         *         based on the provided arguments.
916         * @throws NullPointerException
917         *             if {@code type} or {@code protectionParameter} is {@code
918         *             null}.
919         * @throws IllegalArgumentException
920         *             {@code protectionParameter} not an instance of either
921         *             {@code PasswordProtection} or {@code
922         *             CallbackHandlerProtection}, {@code file} is not a file or
923         *             does not exist at all.
924         */
925        public static Builder newInstance(String type, Provider provider,
926                ProtectionParameter protectionParameter) {
927            if (type == null) {
928                throw new NullPointerException("type == null");
929            }
930            if (protectionParameter == null) {
931                throw new NullPointerException("protectionParameter == null");
932            }
933            return new BuilderImpl(null, protectionParameter, null,
934                    type, provider, AccessController.getContext());
935        }
936
937        /*
938         * This class is implementation of abstract class KeyStore.Builder
939         *
940         * @author Vera Petrashkova
941         *
942         */
943        private static class BuilderImpl extends Builder {
944            // Store used KeyStore
945            private KeyStore keyStore;
946
947            // Store used ProtectionParameter
948            private ProtectionParameter protParameter;
949
950            // Store used KeyStore type
951            private final String typeForKeyStore;
952
953            // Store used KeyStore provider
954            private final Provider providerForKeyStore;
955
956            // Store used file for KeyStore loading
957            private final File fileForLoad;
958
959            // Store getKeyStore method was invoked or not for KeyStoreBuilder
960            private boolean isGetKeyStore = false;
961
962            // Store last Exception in getKeyStore()
963            private KeyStoreException lastException;
964
965            // Store AccessControlContext which is used in getKeyStore() method
966            private final AccessControlContext accControlContext;
967
968            //
969            // Constructor BuilderImpl initializes private fields: keyStore,
970            // protParameter, typeForKeyStore providerForKeyStore fileForLoad,
971            // isGetKeyStore
972            //
973            BuilderImpl(KeyStore ks, ProtectionParameter pp, File file,
974                    String type, Provider provider, AccessControlContext context) {
975                super();
976                keyStore = ks;
977                protParameter = pp;
978                fileForLoad = file;
979                typeForKeyStore = type;
980                providerForKeyStore = provider;
981                isGetKeyStore = false;
982                lastException = null;
983                accControlContext = context;
984            }
985
986            //
987            // Implementation of abstract getKeyStore() method If
988            // KeyStoreBuilder encapsulates KeyStore object then this object is
989            // returned
990            //
991            // If KeyStoreBuilder encapsulates KeyStore type and provider then
992            // KeyStore is created using these parameters. If KeyStoreBuilder
993            // encapsulates file and ProtectionParameter then KeyStore data are
994            // loaded from FileInputStream that is created on file. If file is
995            // not defined then KeyStore object is initialized with null
996            // InputStream and null password.
997            //
998            // Result KeyStore object is returned.
999            //
1000            @Override
1001            public synchronized KeyStore getKeyStore() throws KeyStoreException {
1002                // If KeyStore was created but in final block some exception was
1003                // thrown
1004                // then it was stored in lastException variable and will be
1005                // thrown
1006                // all subsequent calls of this method.
1007                if (lastException != null) {
1008                    throw lastException;
1009                }
1010                if (keyStore != null) {
1011                    isGetKeyStore = true;
1012                    return keyStore;
1013                }
1014
1015                try {
1016                    final KeyStore ks;
1017                    final char[] passwd;
1018
1019                    // get KeyStore instance using type or type and provider
1020                    ks = (providerForKeyStore == null ? KeyStore
1021                            .getInstance(typeForKeyStore) : KeyStore
1022                            .getInstance(typeForKeyStore, providerForKeyStore));
1023                    // protection parameter should be PasswordProtection
1024                    // or CallbackHandlerProtection
1025                    if (protParameter instanceof PasswordProtection) {
1026                        passwd = ((PasswordProtection) protParameter)
1027                                .getPassword();
1028                    } else if (protParameter instanceof CallbackHandlerProtection) {
1029                        passwd = KeyStoreSpi
1030                                .getPasswordFromCallBack(protParameter);
1031                    } else {
1032                        throw new KeyStoreException("protectionParameter is neither PasswordProtection nor CallbackHandlerProtection instance");
1033                    }
1034
1035                    // load KeyStore from file
1036                    AccessController.doPrivileged(
1037                            new PrivilegedExceptionAction<Object>() {
1038                                public Object run() throws Exception {
1039                                    if (fileForLoad != null) {
1040                                        FileInputStream fis = null;
1041                                        try {
1042                                            fis = new FileInputStream(fileForLoad);
1043                                            ks.load(fis, passwd);
1044                                        } finally {
1045                                            // close file input stream
1046                                            if( fis != null ) {
1047                                                fis.close();
1048                                            }
1049                                        }
1050                                    } else {
1051                                        ks.load(new TmpLSParameter(
1052                                                protParameter));
1053                                    }
1054                                    return null;
1055                                }
1056                            }, accControlContext);
1057
1058
1059                    isGetKeyStore = true;
1060                    return ks;
1061                } catch (KeyStoreException e) {
1062                    // Store exception
1063                    throw lastException = e;
1064                } catch (Exception e) {
1065                    // Override exception
1066                    throw lastException = new KeyStoreException(e);
1067                }
1068            }
1069
1070            //
1071            // This is implementation of abstract method
1072            // getProtectionParameter(String alias)
1073            //
1074            // Return: ProtectionParameter to get Entry which was saved in
1075            // KeyStore with defined alias
1076            //
1077            @Override
1078            public synchronized ProtectionParameter getProtectionParameter(
1079                    String alias) throws KeyStoreException {
1080                if (alias == null) {
1081                    throw new NullPointerException("alias == null");
1082                }
1083                if (!isGetKeyStore) {
1084                    throw new IllegalStateException("getKeyStore() was not invoked");
1085                }
1086                return protParameter;
1087            }
1088        }
1089
1090        /*
1091         * Implementation of LoadStoreParameter interface
1092         */
1093        private static class TmpLSParameter implements LoadStoreParameter {
1094
1095            // Store used protection parameter
1096            private final ProtectionParameter protPar;
1097
1098            /**
1099             * Creates TmpLoadStoreParameter object
1100             * @param protPar protection parameter
1101             */
1102            public TmpLSParameter(ProtectionParameter protPar) {
1103                this.protPar = protPar;
1104            }
1105
1106            /**
1107             * This method returns protection parameter
1108             */
1109            public ProtectionParameter getProtectionParameter() {
1110                return protPar;
1111            }
1112        }
1113    }
1114
1115    /**
1116     * {@code CallbackHandlerProtection} is a {@code ProtectionParameter} that
1117     * encapsulates a {@link CallbackHandler}.
1118     */
1119    public static class CallbackHandlerProtection implements
1120            ProtectionParameter {
1121        // Store CallbackHandler
1122        private final CallbackHandler callbackHandler;
1123
1124        /**
1125         * Constructs a new instance of {@code CallbackHandlerProtection} with
1126         * the {@code CallbackHandler}.
1127         *
1128         * @param handler
1129         *            the {@code CallbackHandler}.
1130         * @throws NullPointerException
1131         *             if {@code handler} is {@code null}.
1132         */
1133        public CallbackHandlerProtection(CallbackHandler handler) {
1134            if (handler == null) {
1135                throw new NullPointerException("handler == null");
1136            }
1137            this.callbackHandler = handler;
1138        }
1139
1140        /**
1141         * Returns the {@code CallbackHandler}.
1142         *
1143         * @return the {@code CallbackHandler}.
1144         */
1145        public CallbackHandler getCallbackHandler() {
1146            return callbackHandler;
1147        }
1148    }
1149
1150    /**
1151     * {@code Entry} is the common marker interface for a {@code KeyStore}
1152     * entry.
1153     */
1154    public static interface Entry {
1155    }
1156
1157    /**
1158     * {@code LoadStoreParameter} represents a parameter that specifies how a
1159     * {@code KeyStore} can be loaded and stored.
1160     *
1161     * @see KeyStore#load(LoadStoreParameter)
1162     * @see KeyStore#store(LoadStoreParameter)
1163     */
1164    public static interface LoadStoreParameter {
1165        /**
1166         * Returns the {@code ProtectionParameter} which is used to protect data
1167         * in the {@code KeyStore}.
1168         *
1169         * @return the {@code ProtectionParameter} which is used to protect data
1170         *         in the {@code KeyStore}, maybe {@code null}.
1171         */
1172        public ProtectionParameter getProtectionParameter();
1173    }
1174
1175    /**
1176     * {@code PasswordProtection} is a {@code ProtectionParameter} that protects
1177     * a {@code KeyStore} using a password.
1178     */
1179    public static class PasswordProtection implements ProtectionParameter,
1180            Destroyable {
1181
1182        // Store password
1183        private char[] password;
1184
1185        private boolean isDestroyed = false;
1186
1187        /**
1188         * Constructs a new instance of {@code PasswordProtection} with a
1189         * password. A copy of the password is stored in the new {@code
1190         * PasswordProtection} object.
1191         *
1192         * @param password
1193         *            the password, maybe {@code null}.
1194         */
1195        public PasswordProtection(char[] password) {
1196            if (password != null) {
1197                this.password = password.clone();
1198            }
1199        }
1200
1201        /**
1202         * Returns the password.
1203         *
1204         * @return the password.
1205         * @throws IllegalStateException
1206         *             if the password has been destroyed.
1207         */
1208        public synchronized char[] getPassword() {
1209            if (isDestroyed) {
1210                throw new IllegalStateException("Password was destroyed");
1211            }
1212            return password;
1213        }
1214
1215        /**
1216         * Destroys / invalidates the password.
1217         *
1218         * @throws DestroyFailedException
1219         *             if the password could not be invalidated.
1220         */
1221        public synchronized void destroy() throws DestroyFailedException {
1222            isDestroyed = true;
1223            if (password != null) {
1224                Arrays.fill(password, '\u0000');
1225                password = null;
1226            }
1227        }
1228
1229        /**
1230         * Indicates whether the password is invalidated.
1231         *
1232         * @return {@code true} if the password is invalidated, {@code false}
1233         *         otherwise.
1234         */
1235        public synchronized boolean isDestroyed() {
1236            return isDestroyed;
1237        }
1238    }
1239
1240    /**
1241     * {@code ProtectionParameter} is a marker interface for protection
1242     * parameters. A protection parameter is used to protect the content of a
1243     * {@code KeyStore}.
1244     */
1245    public static interface ProtectionParameter {
1246    }
1247
1248    /**
1249     * {@code PrivateKeyEntry} represents a {@code KeyStore} entry that
1250     * holds a private key.
1251     */
1252    public static final class PrivateKeyEntry implements Entry {
1253        // Store Certificate chain
1254        private Certificate[] chain;
1255
1256        // Store PrivateKey
1257        private PrivateKey privateKey;
1258
1259        /**
1260         * Constructs a new instance of {@code PrivateKeyEntry} with the given
1261         * {@code PrivateKey} and the provided certificate chain.
1262         *
1263         * @param privateKey
1264         *            the private key.
1265         * @param chain
1266         *            the ordered certificate chain with the certificate
1267         *            corresponding to the private key at index 0.
1268         * @throws NullPointerException
1269         *             if {@code privateKey} or {@code chain} is {@code null}.
1270         * @throws IllegalArgumentException
1271         *             if {@code chain.length == 0}, the algorithm of the
1272         *             private key does not match the algorithm of the public
1273         *             key of the first certificate or the certificates are not
1274         *             all of the same type.
1275         */
1276        public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) {
1277            if (privateKey == null) {
1278                throw new NullPointerException("privateKey == null");
1279            }
1280            if (chain == null) {
1281                throw new NullPointerException("chain == null");
1282            }
1283
1284            if (chain.length == 0) {
1285                throw new IllegalArgumentException("chain.length == 0");
1286            }
1287            // Match algorithm of private key and algorithm of public key from
1288            // the end certificate
1289            String s = chain[0].getType();
1290            if (!(chain[0].getPublicKey().getAlgorithm()).equals(privateKey.getAlgorithm())) {
1291                throw new IllegalArgumentException("Algorithm of private key does not match " +
1292                        "algorithm of public key in end certificate of entry (with index number: 0)");
1293            }
1294            // Match certificate types
1295            for (int i = 1; i < chain.length; i++) {
1296                if (!s.equals(chain[i].getType())) {
1297                    throw new IllegalArgumentException("Certificates from the given chain have different types");
1298                }
1299            }
1300            // clone chain - this.chain = (Certificate[])chain.clone();
1301            boolean isAllX509Certificates = true;
1302            // assert chain length > 0
1303            for(Certificate cert: chain){
1304                if(!(cert instanceof X509Certificate)){
1305                    isAllX509Certificates = false;
1306                    break;
1307                }
1308            }
1309
1310            if(isAllX509Certificates){
1311                this.chain = new X509Certificate[chain.length];
1312            } else {
1313                this.chain = new Certificate[chain.length];
1314            }
1315            System.arraycopy(chain, 0, this.chain, 0, chain.length);
1316            this.privateKey = privateKey;
1317        }
1318
1319        /**
1320         * Returns the private key.
1321         *
1322         * @return the private key.
1323         */
1324        public PrivateKey getPrivateKey() {
1325            return privateKey;
1326        }
1327
1328        /**
1329         * Returns the certificate chain.
1330         *
1331         * @return the certificate chain.
1332         */
1333        public Certificate[] getCertificateChain() {
1334            return chain.clone();
1335        }
1336
1337        /**
1338         * Returns the certificate corresponding to the private key.
1339         *
1340         * @return the certificate corresponding to the private key.
1341         */
1342        public Certificate getCertificate() {
1343            return chain[0];
1344        }
1345
1346        /**
1347         * Returns a string containing a concise, human-readable description of
1348         * this {@code PrivateKeyEntry}.
1349         *
1350         * @return a printable representation for this {@code PrivateKeyEntry}.
1351         */
1352        @Override
1353        public String toString() {
1354            StringBuilder sb = new StringBuilder(
1355                    "PrivateKeyEntry: number of elements in certificate chain is ");
1356            sb.append(Integer.toString(chain.length));
1357            sb.append("\n");
1358            for (int i = 0; i < chain.length; i++) {
1359                sb.append(chain[i].toString());
1360                sb.append("\n");
1361            }
1362            return sb.toString();
1363        }
1364    }
1365
1366    /**
1367     * {@code SecretKeyEntry} represents a {@code KeyStore} entry that
1368     * holds a secret key.
1369     */
1370    public static final class SecretKeyEntry implements Entry {
1371
1372        // Store SecretKey
1373        private final SecretKey secretKey;
1374
1375        /**
1376         * Constructs a new instance of {@code SecretKeyEntry} with the given
1377         * {@code SecretKey}.
1378         *
1379         * @param secretKey
1380         *            the secret key.
1381         * @throws NullPointerException
1382         *             if {@code secretKey} is {@code null}.
1383         */
1384        public SecretKeyEntry(SecretKey secretKey) {
1385            if (secretKey == null) {
1386                throw new NullPointerException("secretKey == null");
1387            }
1388            this.secretKey = secretKey;
1389        }
1390
1391        /**
1392         * Returns the secret key.
1393         *
1394         * @return the secret key.
1395         */
1396        public SecretKey getSecretKey() {
1397            return secretKey;
1398        }
1399
1400        /**
1401         * Returns a string containing a concise, human-readable description of
1402         * this {@code SecretKeyEntry}.
1403         *
1404         * @return a printable representation for this {@code
1405         *         SecretKeyEntry}.
1406         */
1407        @Override
1408        public String toString() {
1409            StringBuilder sb = new StringBuilder("SecretKeyEntry: algorithm - ");
1410            sb.append(secretKey.getAlgorithm());
1411            return sb.toString();
1412        }
1413    }
1414
1415    /**
1416     * {@code TrustedCertificateEntry} represents a {@code KeyStore} entry that
1417     * holds a trusted certificate.
1418     */
1419    public static final class TrustedCertificateEntry implements Entry {
1420
1421        // Store trusted Certificate
1422        private final Certificate trustCertificate;
1423
1424        /**
1425         * Constructs a new instance of {@code TrustedCertificateEntry} with the
1426         * given {@code Certificate}.
1427         *
1428         * @param trustCertificate
1429         *            the trusted certificate.
1430         * @throws NullPointerException
1431         *             if {@code trustCertificate} is {@code null}.
1432         */
1433        public TrustedCertificateEntry(Certificate trustCertificate) {
1434            if (trustCertificate == null) {
1435                throw new NullPointerException("trustCertificate == null");
1436            }
1437            this.trustCertificate = trustCertificate;
1438        }
1439
1440        /**
1441         * Returns the trusted certificate.
1442         *
1443         * @return the trusted certificate.
1444         */
1445        public Certificate getTrustedCertificate() {
1446            return trustCertificate;
1447        }
1448
1449        /**
1450         * Returns a string containing a concise, human-readable description of
1451         * this {@code TrustedCertificateEntry}.
1452         *
1453         * @return a printable representation for this {@code
1454         *         TrustedCertificateEntry}.
1455         */
1456        @Override
1457        public String toString() {
1458            return "Trusted certificate entry:\n" + trustCertificate;
1459        }
1460    }
1461}
1462