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