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