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