KeyStore.java revision fb0ec0e650bf8be35acb0d47da0311a7c446aa33
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) throws KeyStoreException {
180        // check parameters
181        if (provider == null) {
182            throw new IllegalArgumentException();
183        }
184        if (type == null) {
185            throw new NullPointerException();
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.getMessage());
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(PROPERTYNAME);
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                super();
914                keyStore = ks;
915                protParameter = pp;
916                fileForLoad = file;
917                typeForKeyStore = type;
918                providerForKeyStore = provider;
919                isGetKeyStore = false;
920                lastException = null;
921            }
922
923            /**
924             * Implementation of abstract getKeyStore() method If
925             * KeyStoreBuilder encapsulates KeyStore object then this object is
926             * returned
927             *
928             * If KeyStoreBuilder encapsulates KeyStore type and provider then
929             * KeyStore is created using these parameters. If KeyStoreBuilder
930             * encapsulates file and ProtectionParameter then KeyStore data are
931             * loaded from FileInputStream that is created on file. If file is
932             * not defined then KeyStore object is initialized with null
933             * InputStream and null password.
934             *
935             * Result KeyStore object is returned.
936             */
937            @Override
938            public synchronized KeyStore getKeyStore() throws KeyStoreException {
939                // If KeyStore was created but in final block some exception was
940                // thrown
941                // then it was stored in lastException variable and will be
942                // thrown
943                // all subsequent calls of this method.
944                if (lastException != null) {
945                    throw lastException;
946                }
947                if (keyStore != null) {
948                    isGetKeyStore = true;
949                    return keyStore;
950                }
951
952                try {
953                    // get KeyStore instance using type or type and provider
954                    final KeyStore ks = (providerForKeyStore == null ? KeyStore
955                            .getInstance(typeForKeyStore) : KeyStore
956                            .getInstance(typeForKeyStore, providerForKeyStore));
957                    // protection parameter should be PasswordProtection
958                    // or CallbackHandlerProtection
959                    final char[] passwd;
960                    if (protParameter instanceof PasswordProtection) {
961                        passwd = ((PasswordProtection) protParameter)
962                                .getPassword();
963                    } else if (protParameter instanceof CallbackHandlerProtection) {
964                        passwd = KeyStoreSpi
965                                .getPasswordFromCallBack(protParameter);
966                    } else {
967                        throw new KeyStoreException("protectionParameter is neither "
968                                + "PasswordProtection nor CallbackHandlerProtection instance");
969                    }
970
971                    // load KeyStore from file
972                    if (fileForLoad != null) {
973                        FileInputStream fis = null;
974                        try {
975                            fis = new FileInputStream(fileForLoad);
976                            ks.load(fis, passwd);
977                        } finally {
978                            IoUtils.closeQuietly(fis);
979                        }
980                    } else {
981                        ks.load(new TmpLSParameter(protParameter));
982                    }
983
984                    isGetKeyStore = true;
985                    return ks;
986                } catch (KeyStoreException e) {
987                    // Store exception
988                    throw lastException = e;
989                } catch (Exception e) {
990                    // Override exception
991                    throw lastException = new KeyStoreException(e);
992                }
993            }
994
995            /**
996             * This is implementation of abstract method
997             * getProtectionParameter(String alias)
998             *
999             * Return: ProtectionParameter to get Entry which was saved in
1000             * KeyStore with defined alias
1001             */
1002            @Override
1003            public synchronized ProtectionParameter getProtectionParameter(
1004                    String alias) throws KeyStoreException {
1005                if (alias == null) {
1006                    throw new NullPointerException("alias == null");
1007                }
1008                if (!isGetKeyStore) {
1009                    throw new IllegalStateException("getKeyStore() was not invoked");
1010                }
1011                return protParameter;
1012            }
1013        }
1014
1015        /*
1016         * Implementation of LoadStoreParameter interface
1017         */
1018        private static class TmpLSParameter implements LoadStoreParameter {
1019
1020            // Store used protection parameter
1021            private final ProtectionParameter protPar;
1022
1023            /**
1024             * Creates TmpLoadStoreParameter object
1025             * @param protPar protection parameter
1026             */
1027            public TmpLSParameter(ProtectionParameter protPar) {
1028                this.protPar = protPar;
1029            }
1030
1031            /**
1032             * This method returns protection parameter
1033             */
1034            public ProtectionParameter getProtectionParameter() {
1035                return protPar;
1036            }
1037        }
1038    }
1039
1040    /**
1041     * {@code CallbackHandlerProtection} is a {@code ProtectionParameter} that
1042     * encapsulates a {@link CallbackHandler}.
1043     */
1044    public static class CallbackHandlerProtection implements
1045            ProtectionParameter {
1046        // Store CallbackHandler
1047        private final CallbackHandler callbackHandler;
1048
1049        /**
1050         * Constructs a new instance of {@code CallbackHandlerProtection} with
1051         * the {@code CallbackHandler}.
1052         *
1053         * @param handler
1054         *            the {@code CallbackHandler}.
1055         * @throws NullPointerException
1056         *             if {@code handler} is {@code null}.
1057         */
1058        public CallbackHandlerProtection(CallbackHandler handler) {
1059            if (handler == null) {
1060                throw new NullPointerException("handler == null");
1061            }
1062            this.callbackHandler = handler;
1063        }
1064
1065        /**
1066         * Returns the {@code CallbackHandler}.
1067         *
1068         * @return the {@code CallbackHandler}.
1069         */
1070        public CallbackHandler getCallbackHandler() {
1071            return callbackHandler;
1072        }
1073    }
1074
1075    /**
1076     * {@code Entry} is the common marker interface for a {@code KeyStore}
1077     * entry.
1078     */
1079    public static interface Entry {
1080    }
1081
1082    /**
1083     * {@code LoadStoreParameter} represents a parameter that specifies how a
1084     * {@code KeyStore} can be loaded and stored.
1085     *
1086     * @see KeyStore#load(LoadStoreParameter)
1087     * @see KeyStore#store(LoadStoreParameter)
1088     */
1089    public static interface LoadStoreParameter {
1090        /**
1091         * Returns the {@code ProtectionParameter} which is used to protect data
1092         * in the {@code KeyStore}.
1093         *
1094         * @return the {@code ProtectionParameter} which is used to protect data
1095         *         in the {@code KeyStore}, maybe {@code null}.
1096         */
1097        public ProtectionParameter getProtectionParameter();
1098    }
1099
1100    /**
1101     * {@code PasswordProtection} is a {@code ProtectionParameter} that protects
1102     * a {@code KeyStore} using a password.
1103     */
1104    public static class PasswordProtection implements ProtectionParameter,
1105            Destroyable {
1106
1107        // Store password
1108        private char[] password;
1109
1110        private boolean isDestroyed = false;
1111
1112        /**
1113         * Constructs a new instance of {@code PasswordProtection} with a
1114         * password. A copy of the password is stored in the new {@code
1115         * PasswordProtection} object.
1116         *
1117         * @param password
1118         *            the password, maybe {@code null}.
1119         */
1120        public PasswordProtection(char[] password) {
1121            if (password != null) {
1122                this.password = password.clone();
1123            }
1124        }
1125
1126        /**
1127         * Returns the password.
1128         *
1129         * @return the password.
1130         * @throws IllegalStateException
1131         *             if the password has been destroyed.
1132         */
1133        public synchronized char[] getPassword() {
1134            if (isDestroyed) {
1135                throw new IllegalStateException("Password was destroyed");
1136            }
1137            return password;
1138        }
1139
1140        /**
1141         * Destroys / invalidates the password.
1142         *
1143         * @throws DestroyFailedException
1144         *             if the password could not be invalidated.
1145         */
1146        public synchronized void destroy() throws DestroyFailedException {
1147            isDestroyed = true;
1148            if (password != null) {
1149                Arrays.fill(password, '\u0000');
1150                password = null;
1151            }
1152        }
1153
1154        /**
1155         * Indicates whether the password is invalidated.
1156         *
1157         * @return {@code true} if the password is invalidated, {@code false}
1158         *         otherwise.
1159         */
1160        public synchronized boolean isDestroyed() {
1161            return isDestroyed;
1162        }
1163    }
1164
1165    /**
1166     * {@code ProtectionParameter} is a marker interface for protection
1167     * parameters. A protection parameter is used to protect the content of a
1168     * {@code KeyStore}.
1169     */
1170    public static interface ProtectionParameter {
1171    }
1172
1173    /**
1174     * {@code PrivateKeyEntry} represents a {@code KeyStore} entry that
1175     * holds a private key.
1176     */
1177    public static final class PrivateKeyEntry implements Entry {
1178        // Store Certificate chain
1179        private Certificate[] chain;
1180
1181        // Store PrivateKey
1182        private PrivateKey privateKey;
1183
1184        /**
1185         * Constructs a new instance of {@code PrivateKeyEntry} with the given
1186         * {@code PrivateKey} and the provided certificate chain.
1187         *
1188         * @param privateKey
1189         *            the private key.
1190         * @param chain
1191         *            the ordered certificate chain with the certificate
1192         *            corresponding to the private key at index 0.
1193         * @throws NullPointerException
1194         *             if {@code privateKey} or {@code chain} is {@code null}.
1195         * @throws IllegalArgumentException
1196         *             if {@code chain.length == 0}, the algorithm of the
1197         *             private key does not match the algorithm of the public
1198         *             key of the first certificate or the certificates are not
1199         *             all of the same type.
1200         */
1201        public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) {
1202            if (privateKey == null) {
1203                throw new NullPointerException("privateKey == null");
1204            }
1205            if (chain == null) {
1206                throw new NullPointerException("chain == null");
1207            }
1208
1209            if (chain.length == 0) {
1210                throw new IllegalArgumentException("chain.length == 0");
1211            }
1212            // Match algorithm of private key and algorithm of public key from
1213            // the end certificate
1214            String s = chain[0].getType();
1215            if (!(chain[0].getPublicKey().getAlgorithm()).equals(privateKey.getAlgorithm())) {
1216                throw new IllegalArgumentException("Algorithm of private key does not match "
1217                        + "algorithm of public key in end certificate of entry "
1218                        + "(with index number: 0)");
1219            }
1220            // Match certificate types
1221            for (int i = 1; i < chain.length; i++) {
1222                if (!s.equals(chain[i].getType())) {
1223                    throw new IllegalArgumentException("Certificates from the given chain have "
1224                                                       + "different types");
1225                }
1226            }
1227            // clone chain - this.chain = (Certificate[])chain.clone();
1228            boolean isAllX509Certificates = true;
1229            // assert chain length > 0
1230            for(Certificate cert: chain){
1231                if(!(cert instanceof X509Certificate)){
1232                    isAllX509Certificates = false;
1233                    break;
1234                }
1235            }
1236
1237            if(isAllX509Certificates){
1238                this.chain = new X509Certificate[chain.length];
1239            } else {
1240                this.chain = new Certificate[chain.length];
1241            }
1242            System.arraycopy(chain, 0, this.chain, 0, chain.length);
1243            this.privateKey = privateKey;
1244        }
1245
1246        /**
1247         * Returns the private key.
1248         *
1249         * @return the private key.
1250         */
1251        public PrivateKey getPrivateKey() {
1252            return privateKey;
1253        }
1254
1255        /**
1256         * Returns the certificate chain.
1257         *
1258         * @return the certificate chain.
1259         */
1260        public Certificate[] getCertificateChain() {
1261            return chain.clone();
1262        }
1263
1264        /**
1265         * Returns the certificate corresponding to the private key.
1266         *
1267         * @return the certificate corresponding to the private key.
1268         */
1269        public Certificate getCertificate() {
1270            return chain[0];
1271        }
1272
1273        /**
1274         * Returns a string containing a concise, human-readable description of
1275         * this {@code PrivateKeyEntry}.
1276         *
1277         * @return a printable representation for this {@code PrivateKeyEntry}.
1278         */
1279        @Override
1280        public String toString() {
1281            StringBuilder sb = new StringBuilder(
1282                    "PrivateKeyEntry: number of elements in certificate chain is ");
1283            sb.append(Integer.toString(chain.length));
1284            sb.append("\n");
1285            for (int i = 0; i < chain.length; i++) {
1286                sb.append(chain[i].toString());
1287                sb.append("\n");
1288            }
1289            return sb.toString();
1290        }
1291    }
1292
1293    /**
1294     * {@code SecretKeyEntry} represents a {@code KeyStore} entry that
1295     * holds a secret key.
1296     */
1297    public static final class SecretKeyEntry implements Entry {
1298
1299        // Store SecretKey
1300        private final SecretKey secretKey;
1301
1302        /**
1303         * Constructs a new instance of {@code SecretKeyEntry} with the given
1304         * {@code SecretKey}.
1305         *
1306         * @param secretKey
1307         *            the secret key.
1308         * @throws NullPointerException
1309         *             if {@code secretKey} is {@code null}.
1310         */
1311        public SecretKeyEntry(SecretKey secretKey) {
1312            if (secretKey == null) {
1313                throw new NullPointerException("secretKey == null");
1314            }
1315            this.secretKey = secretKey;
1316        }
1317
1318        /**
1319         * Returns the secret key.
1320         *
1321         * @return the secret key.
1322         */
1323        public SecretKey getSecretKey() {
1324            return secretKey;
1325        }
1326
1327        /**
1328         * Returns a string containing a concise, human-readable description of
1329         * this {@code SecretKeyEntry}.
1330         *
1331         * @return a printable representation for this {@code
1332         *         SecretKeyEntry}.
1333         */
1334        @Override
1335        public String toString() {
1336            StringBuilder sb = new StringBuilder("SecretKeyEntry: algorithm - ");
1337            sb.append(secretKey.getAlgorithm());
1338            return sb.toString();
1339        }
1340    }
1341
1342    /**
1343     * {@code TrustedCertificateEntry} represents a {@code KeyStore} entry that
1344     * holds a trusted certificate.
1345     */
1346    public static final class TrustedCertificateEntry implements Entry {
1347
1348        // Store trusted Certificate
1349        private final Certificate trustCertificate;
1350
1351        /**
1352         * Constructs a new instance of {@code TrustedCertificateEntry} with the
1353         * given {@code Certificate}.
1354         *
1355         * @param trustCertificate
1356         *            the trusted certificate.
1357         * @throws NullPointerException
1358         *             if {@code trustCertificate} is {@code null}.
1359         */
1360        public TrustedCertificateEntry(Certificate trustCertificate) {
1361            if (trustCertificate == null) {
1362                throw new NullPointerException("trustCertificate == null");
1363            }
1364            this.trustCertificate = trustCertificate;
1365        }
1366
1367        /**
1368         * Returns the trusted certificate.
1369         *
1370         * @return the trusted certificate.
1371         */
1372        public Certificate getTrustedCertificate() {
1373            return trustCertificate;
1374        }
1375
1376        /**
1377         * Returns a string containing a concise, human-readable description of
1378         * this {@code TrustedCertificateEntry}.
1379         *
1380         * @return a printable representation for this {@code
1381         *         TrustedCertificateEntry}.
1382         */
1383        @Override
1384        public String toString() {
1385            return "Trusted certificate entry:\n" + trustCertificate;
1386        }
1387    }
1388}
1389