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