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