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