OSDN Git Service

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