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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package java.security;
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.security.cert.Certificate;
26 import java.security.cert.CertificateException;
27 import java.security.cert.X509Certificate;
28 import java.util.Arrays;
29 import java.util.Date;
30 import java.util.Enumeration;
31 import javax.crypto.SecretKey;
32 import javax.security.auth.DestroyFailedException;
33 import javax.security.auth.Destroyable;
34 import javax.security.auth.callback.CallbackHandler;
35 import org.apache.harmony.security.fortress.Engine;
38 * {@code KeyStore} is responsible for maintaining cryptographic keys and their
41 * The type of the system key store can be changed by setting the {@code
42 * 'keystore.type'} property in the file named {@code
43 * JAVA_HOME/lib/security/java.security}.
48 public class KeyStore {
50 // Store KeyStore SERVICE name
51 private static final String SERVICE = "KeyStore";
53 // Used to access common engine functionality
54 private static Engine engine = new Engine(SERVICE);
56 // Store KeyStore property name
57 private static final String PROPERTYNAME = "keystore.type";
59 // Store default KeyStore type
60 private static final String DEFAULT_KEYSTORE_TYPE = "jks";
62 // Store KeyStore state (initialized or not)
63 private boolean isInit;
65 // Store used KeyStoreSpi
66 private final KeyStoreSpi implSpi;
68 // Store used provider
69 private final Provider provider;
72 private final String type;
75 * Constructs a new instance of {@code KeyStore} with the given arguments.
78 * the concrete key store.
82 * the type of the {@code KeyStore} to be constructed.
84 protected KeyStore(KeyStoreSpi keyStoreSpi, Provider provider, String type) {
86 this.provider = provider;
87 this.implSpi = keyStoreSpi;
92 * Throws the standard "keystore not initialized" exception.
94 private static void throwNotInitialized() throws KeyStoreException {
95 throw new KeyStoreException("KeyStore was not initialized");
99 * Returns a new instance of {@code KeyStore} with the specified type.
102 * the type of the returned {@code KeyStore}.
103 * @return a new instance of {@code KeyStore} with the specified type.
104 * @throws KeyStoreException
105 * if an error occurred during the creation of the new {@code
107 * @throws NullPointerException if {@code type == null}
108 * @see #getDefaultType
110 public static KeyStore getInstance(String type) throws KeyStoreException {
112 throw new NullPointerException();
114 synchronized (engine) {
116 engine.getInstance(type, null);
117 return new KeyStore((KeyStoreSpi) engine.spi, engine.provider, type);
118 } catch (NoSuchAlgorithmException e) {
119 throw new KeyStoreException(e.getMessage());
125 * Returns a new instance of {@code KeyStore} from the specified provider
126 * with the given type.
129 * the type of the returned {@code KeyStore}.
131 * name of the provider of the {@code KeyStore}.
132 * @return a new instance of {@code KeyStore} from the specified provider
133 * with the given type.
134 * @throws KeyStoreException
135 * if an error occurred during the creation of the new {@code
137 * @throws NoSuchProviderException
138 * if the specified provider is not available.
139 * @throws IllegalArgumentException if {@code provider == null || provider.isEmpty()}
140 * @throws NullPointerException
141 * if {@code type} is {@code null} (instead of
142 * NoSuchAlgorithmException) as in 1.4 release
143 * @see #getDefaultType
145 public static KeyStore getInstance(String type, String provider)
146 throws KeyStoreException, NoSuchProviderException {
147 if (provider == null || provider.isEmpty()) {
148 throw new IllegalArgumentException();
150 Provider impProvider = Security.getProvider(provider);
151 if (impProvider == null) {
152 throw new NoSuchProviderException(provider);
155 return getInstance(type, impProvider);
156 } catch (Exception e) {
157 throw new KeyStoreException(e.getMessage(), e);
162 * Returns a new instance of {@code KeyStore} from the specified provider
163 * with the given type.
166 * the type of the returned {@code KeyStore}.
168 * the provider of the {@code KeyStore}.
169 * @return a new instance of {@code KeyStore} from the specified provider
170 * with the given type.
171 * @throws KeyStoreException
172 * if an error occurred during the creation of the new {@code
174 * @throws IllegalArgumentException
175 * if {@code provider} is {@code null} or the empty string.
176 * @throws NullPointerException if {@code type == null} (instead of
177 * NoSuchAlgorithmException) as in 1.4 release
178 * @see #getDefaultType
180 public static KeyStore getInstance(String type, Provider provider)
181 throws KeyStoreException {
183 if (provider == null) {
184 throw new IllegalArgumentException();
187 throw new NullPointerException();
189 // return KeyStore instance
190 synchronized (engine) {
192 engine.getInstance(type, provider, null);
193 return new KeyStore((KeyStoreSpi) engine.spi, provider, type);
194 } catch (Exception e) {
195 // override exception
196 throw new KeyStoreException(e.getMessage());
202 * Returns the default type for {@code KeyStore} instances.
204 * The default is specified in the {@code 'keystore.type'} property in the
205 * file named {@code JAVA_HOME/lib/security/java.security}. If this property
206 * is not set, {@code "jks"} will be used.
208 * @return the default type for {@code KeyStore} instances
210 public static final String getDefaultType() {
211 String dt = AccessController.doPrivileged(
212 new PrivilegedAction<String>() {
213 public String run() {
214 return Security.getProperty(PROPERTYNAME);
218 return (dt == null ? DEFAULT_KEYSTORE_TYPE : dt);
222 * Returns the provider associated with this {@code KeyStore}.
224 * @return the provider associated with this {@code KeyStore}.
226 public final Provider getProvider() {
231 * Returns the type of this {@code KeyStore}.
233 * @return the type of this {@code KeyStore}.
235 public final String getType() {
240 * Returns the key with the given alias, using the password to recover the
241 * key from the store.
244 * the alias for the entry.
246 * the password used to recover the key.
247 * @return the key with the specified alias, or {@code null} if the
248 * specified alias is not bound to an entry.
249 * @throws KeyStoreException
250 * if this {@code KeyStore} is not initialized.
251 * @throws NoSuchAlgorithmException
252 * if the algorithm for recovering the key is not available.
253 * @throws UnrecoverableKeyException
254 * if the key can not be recovered.
256 public final Key getKey(String alias, char[] password)
257 throws KeyStoreException, NoSuchAlgorithmException,
258 UnrecoverableKeyException {
260 // BEGIN android-changed
261 throwNotInitialized();
262 // END android-changed
264 return implSpi.engineGetKey(alias, password);
268 * Returns the certificate chain for the entry with the given alias.
271 * the alias for the entry.
272 * @return the certificate chain for the entry with the given alias, or
273 * {@code null} if the specified alias is not bound to an entry.
274 * @throws KeyStoreException
275 * if this {@code KeyStore} is not initialized.
277 public final Certificate[] getCertificateChain(String alias)
278 throws KeyStoreException {
280 // BEGIN android-changed
281 throwNotInitialized();
282 // END android-changed
284 return implSpi.engineGetCertificateChain(alias);
288 * Returns the trusted certificate for the entry with the given alias.
291 * the alias for the entry.
292 * @return the trusted certificate for the entry with the given alias, or
293 * {@code null} if the specified alias is not bound to an entry.
294 * @throws KeyStoreException
295 * if this {@code KeyStore} is not initialized.
297 public final Certificate getCertificate(String alias)
298 throws KeyStoreException {
300 // BEGIN android-changed
301 throwNotInitialized();
302 // END android-changed
304 return implSpi.engineGetCertificate(alias);
308 * Returns the creation date of the entry with the given alias.
311 * the alias for the entry.
312 * @return the creation date, or {@code null} if the specified alias is not
314 * @throws KeyStoreException
315 * if this {@code KeyStore} is not initialized.
317 public final Date getCreationDate(String alias) throws KeyStoreException {
319 // BEGIN android-changed
320 throwNotInitialized();
321 // END android-changed
323 return implSpi.engineGetCreationDate(alias);
327 * Associates the given alias with the key, password and certificate chain.
329 * If the specified alias already exists, it will be reassigned.
332 * the alias for the key.
338 * the certificate chain.
339 * @throws KeyStoreException
340 * if this {@code KeyStore} is not initialized.
341 * @throws IllegalArgumentException
342 * if {@code key} is a {@code PrivateKey} and {@code chain} does
343 * not contain any certificates.
344 * @throws NullPointerException
345 * if {@code alias} is {@code null}.
347 public final void setKeyEntry(String alias, Key key, char[] password,
348 Certificate[] chain) throws KeyStoreException {
350 // BEGIN android-changed
351 throwNotInitialized();
352 // END android-changed
355 // Certificate chain is required for PrivateKey
356 if (null != key && key instanceof PrivateKey && (chain == null || chain.length == 0)) {
357 throw new IllegalArgumentException("Certificate chain is not defined for Private key");
359 implSpi.engineSetKeyEntry(alias, key, password, chain);
363 * Associates the given alias with a key and a certificate chain.
365 * If the specified alias already exists, it will be reassigned.
367 * If this {@code KeyStore} is of type {@code "jks"}, {@code key} must be
368 * encoded conform to the PKS#8 standard as an
369 * {@link javax.crypto.EncryptedPrivateKeyInfo}.
372 * the alias for the key.
374 * the key in an encoded format.
376 * the certificate chain.
377 * @throws KeyStoreException
378 * if this {@code KeyStore} is not initialized or if {@code key}
380 * @throws IllegalArgumentException
381 * if {@code key} is a {@code PrivateKey} and {@code chain}
383 * @throws NullPointerException
384 * if {@code alias} is {@code null}.
386 public final void setKeyEntry(String alias, byte[] key, Certificate[] chain)
387 throws KeyStoreException {
389 // BEGIN android-changed
390 throwNotInitialized();
391 // END android-changed
393 implSpi.engineSetKeyEntry(alias, key, chain);
397 * Associates the given alias with a certificate.
399 * If the specified alias already exists, it will be reassigned.
402 * the alias for the certificate.
405 * @throws KeyStoreException
406 * if this {@code KeyStore} is not initialized, or an existing
407 * alias is not associated to an entry containing a trusted
408 * certificate, or this method fails for any other reason.
409 * @throws NullPointerException
410 * if {@code alias} is {@code null}.
412 public final void setCertificateEntry(String alias, Certificate cert)
413 throws KeyStoreException {
415 // BEGIN android-changed
416 throwNotInitialized();
417 // END android-changed
419 implSpi.engineSetCertificateEntry(alias, cert);
423 * Deletes the entry identified with the given alias from this {@code
427 * the alias for the entry.
428 * @throws KeyStoreException
429 * if this {@code KeyStore} is not initialized, or if the entry
430 * can not be deleted.
432 public final void deleteEntry(String alias) throws KeyStoreException {
434 // BEGIN android-changed
435 throwNotInitialized();
436 // END android-changed
438 implSpi.engineDeleteEntry(alias);
442 * Returns an {@code Enumeration} over all alias names stored in this
445 * @return an {@code Enumeration} over all alias names stored in this
447 * @throws KeyStoreException
448 * if this {@code KeyStore} is not initialized.
450 public final Enumeration<String> aliases() throws KeyStoreException {
452 // BEGIN android-changed
453 throwNotInitialized();
454 // END android-changed
456 return implSpi.engineAliases();
460 * Indicates whether the given alias is present in this {@code KeyStore}.
463 * the alias of an entry.
464 * @return {@code true} if the alias exists, {@code false} otherwise.
465 * @throws KeyStoreException
466 * if this {@code KeyStore} is not initialized.
468 public final boolean containsAlias(String alias) throws KeyStoreException {
470 // BEGIN android-changed
471 throwNotInitialized();
472 // END android-changed
474 return implSpi.engineContainsAlias(alias);
478 * Returns the number of entries stored in this {@code KeyStore}.
480 * @return the number of entries stored in this {@code KeyStore}.
481 * @throws KeyStoreException
482 * if this {@code KeyStore} is not initialized.
484 public final int size() throws KeyStoreException {
486 // BEGIN android-changed
487 throwNotInitialized();
488 // END android-changed
490 return implSpi.engineSize();
494 * Indicates whether the specified alias is associated with either a
495 * {@link PrivateKeyEntry} or a {@link SecretKeyEntry}.
498 * the alias of an entry.
499 * @return {@code true} if the given alias is associated with a key entry.
500 * @throws KeyStoreException
501 * if this {@code KeyStore} is not initialized.
503 public final boolean isKeyEntry(String alias) throws KeyStoreException {
505 // BEGIN android-changed
506 throwNotInitialized();
507 // END android-changed
509 return implSpi.engineIsKeyEntry(alias);
513 * Indicates whether the specified alias is associated with a
514 * {@link TrustedCertificateEntry}.
517 * the alias of an entry.
518 * @return {@code true} if the given alias is associated with a certificate
520 * @throws KeyStoreException
521 * if this {@code KeyStore} is not initialized.
523 public final boolean isCertificateEntry(String alias)
524 throws KeyStoreException {
526 // BEGIN android-changed
527 throwNotInitialized();
528 // END android-changed
530 return implSpi.engineIsCertificateEntry(alias);
534 * Returns the alias associated with the first entry whose certificate
535 * matches the specified certificate.
538 * the certificate to find the associated entry's alias for.
539 * @return the alias or {@code null} if no entry with the specified
540 * certificate can be found.
541 * @throws KeyStoreException
542 * if this {@code KeyStore} is not initialized.
544 public final String getCertificateAlias(Certificate cert)
545 throws KeyStoreException {
547 // BEGIN android-changed
548 throwNotInitialized();
549 // END android-changed
551 return implSpi.engineGetCertificateAlias(cert);
555 * Writes this {@code KeyStore} to the specified {@code OutputStream}. The
556 * data written to the {@code OutputStream} is protected by the specified
560 * the {@code OutputStream} to write the store's data to.
562 * the password to protect the data.
563 * @throws KeyStoreException
564 * if this {@code KeyStore} is not initialized.
565 * @throws IOException
566 * if a problem occurred while writing to the stream.
567 * @throws NoSuchAlgorithmException
568 * if the required algorithm is not available.
569 * @throws CertificateException
570 * if an exception occurred while storing the certificates of
571 * this {@code KeyStore}.
573 public final void store(OutputStream stream, char[] password)
574 throws KeyStoreException, IOException, NoSuchAlgorithmException,
575 CertificateException {
577 // BEGIN android-changed
578 throwNotInitialized();
579 // END android-changed
582 //Just delegate stream and password to implSpi
583 implSpi.engineStore(stream, password);
587 * Stores this {@code KeyStore} using the specified {@code
588 * LoadStoreParameter}.
591 * the {@code LoadStoreParameter} that specifies how to store
592 * this {@code KeyStore}, maybe {@code null}.
593 * @throws KeyStoreException
594 * if this {@code KeyStore} is not initialized.
595 * @throws IOException
596 * if a problem occurred while writing to the stream.
597 * @throws NoSuchAlgorithmException
598 * if the required algorithm is not available.
599 * @throws CertificateException
600 * if an exception occurred while storing the certificates of
601 * this {@code KeyStore}.
602 * @throws IllegalArgumentException
603 * if the given {@link LoadStoreParameter} is not recognized.
605 public final void store(LoadStoreParameter param) throws KeyStoreException,
606 IOException, NoSuchAlgorithmException, CertificateException {
608 // BEGIN android-changed
609 throwNotInitialized();
610 // END android-changed
612 implSpi.engineStore(param);
616 * Initializes this {@code KeyStore} from the provided {@code InputStream}.
617 * Pass {@code null} as the {@code stream} argument to initialize an empty
618 * {@code KeyStore} or to initialize a {@code KeyStore} which does not rely
619 * on an {@code InputStream}. This {@code KeyStore} utilizes the given
620 * password to verify the stored data.
623 * the {@code InputStream} to load this {@code KeyStore}'s data
624 * from or {@code null}.
626 * the password to verify the stored data, maybe {@code null}.
627 * @throws IOException
628 * if a problem occurred while reading from the stream.
629 * @throws NoSuchAlgorithmException
630 * if the required algorithm is not available.
631 * @throws CertificateException
632 * if an exception occurred while loading the certificates of
633 * this {@code KeyStore}.
635 public final void load(InputStream stream, char[] password)
636 throws IOException, NoSuchAlgorithmException, CertificateException {
637 implSpi.engineLoad(stream, password);
642 * Loads this {@code KeyStore} using the specified {@code
643 * LoadStoreParameter}.
646 * the {@code LoadStoreParameter} that specifies how to load this
647 * {@code KeyStore}, maybe {@code null}.
648 * @throws IOException
649 * if a problem occurred while reading from the stream.
650 * @throws NoSuchAlgorithmException
651 * if the required algorithm is not available.
652 * @throws CertificateException
653 * if an exception occurred while loading the certificates of
654 * this {@code KeyStore}.
655 * @throws IllegalArgumentException
656 * if the given {@link LoadStoreParameter} is not recognized.
658 public final void load(LoadStoreParameter param) throws IOException,
659 NoSuchAlgorithmException, CertificateException {
660 implSpi.engineLoad(param);
665 * Returns the {@code Entry} with the given alias, using the specified
666 * {@code ProtectionParameter}.
669 * the alias of the requested entry.
671 * the {@code ProtectionParameter} used to protect the requested
672 * entry, maybe {@code null}.
673 * @return he {@code Entry} with the given alias, using the specified
674 * {@code ProtectionParameter}.
675 * @throws NoSuchAlgorithmException
676 * if the required algorithm is not available.
677 * @throws UnrecoverableEntryException
678 * if the entry can not be recovered.
679 * @throws KeyStoreException
680 * if this {@code KeyStore} is not initialized.
681 * @throws NullPointerException
682 * if {@code alias} is {@code null}.
684 public final Entry getEntry(String alias, ProtectionParameter param)
685 throws NoSuchAlgorithmException, UnrecoverableEntryException,
688 throw new NullPointerException("alias == null");
691 // BEGIN android-changed
692 throwNotInitialized();
693 // END android-changed
695 return implSpi.engineGetEntry(alias, param);
699 * Stores the given {@code Entry} in this {@code KeyStore} and associates
700 * the entry with the given {@code alias}. The entry is protected by the
701 * specified {@code ProtectionParameter}.
703 * If the specified alias already exists, it will be reassigned.
706 * the alias for the entry.
708 * the entry to store.
710 * the {@code ProtectionParameter} to protect the entry.
711 * @throws KeyStoreException
712 * if this {@code KeyStore} is not initialized.
713 * @throws NullPointerException
714 * if {@code alias} is {@code null} or {@code entry} is {@code
717 public final void setEntry(String alias, Entry entry,
718 ProtectionParameter param) throws KeyStoreException {
720 // BEGIN android-changed
721 throwNotInitialized();
722 // END android-changed
725 throw new NullPointerException("alias == null");
728 throw new NullPointerException("entry == null");
730 implSpi.engineSetEntry(alias, entry, param);
734 * Indicates whether the entry for the given alias is assignable to the
735 * provided {@code Class}.
738 * the alias for the entry.
740 * the type of the entry.
741 * @return {@code true} if the {@code Entry} for the alias is assignable to
742 * the specified {@code entryClass}.
743 * @throws KeyStoreException
744 * if this {@code KeyStore} is not initialized.
746 public final boolean entryInstanceOf(String alias,
747 Class<? extends KeyStore.Entry> entryClass)
748 throws KeyStoreException {
750 throw new NullPointerException("alias == null");
752 if (entryClass == null) {
753 throw new NullPointerException("entryClass == null");
757 // BEGIN android-changed
758 throwNotInitialized();
759 // END android-changed
761 return implSpi.engineEntryInstanceOf(alias, entryClass);
765 * {@code Builder} is used to construct new instances of {@code KeyStore}.
767 public abstract static class Builder {
769 * Constructs a new instance of {@code Builder}.
771 protected Builder() {
775 * Returns the {@code KeyStore} created by this {@code Builder}.
777 * @return the {@code KeyStore} created by this {@code Builder}.
778 * @throws KeyStoreException
779 * if an error occurred during construction.
781 public abstract KeyStore getKeyStore() throws KeyStoreException;
784 * Returns the {@code ProtectionParameter} to be used when a {@code
785 * Entry} with the specified alias is requested. Before this method is
786 * invoked, {@link #getKeyStore()} must be called.
789 * the alias for the entry.
790 * @return the {@code ProtectionParameter} to be used when a {@code
791 * Entry} with the specified alias is requested.
792 * @throws KeyStoreException
793 * if an error occurred during the lookup for the protection
795 * @throws IllegalStateException
796 * if {@link #getKeyStore()} is not called prior the
797 * invocation of this method.
798 * @throws NullPointerException
799 * if {@code alias} is {@code null}.
801 public abstract ProtectionParameter getProtectionParameter(String alias)
802 throws KeyStoreException;
805 * Returns a new {@code Builder} that holds the given {@code KeyStore}
806 * and the given {@code ProtectionParameter}.
809 * the {@code KeyStore} to be held.
810 * @param protectionParameter
811 * the {@code ProtectionParameter} to be held.
812 * @return a new instance of {@code Builder} that holds the specified
813 * {@code KeyStore} and the specified {@code
814 * ProtectionParameter}.
815 * @throws NullPointerException
816 * if {@code keyStore} or {@code protectionParameter} is
818 * @throws IllegalArgumentException
819 * if the given {@code KeyStore} is not initialized.
821 public static Builder newInstance(KeyStore keyStore,
822 ProtectionParameter protectionParameter) {
823 if (keyStore == null) {
824 throw new NullPointerException("keyStore == null");
826 if (protectionParameter == null) {
827 throw new NullPointerException("protectionParameter == null");
829 if (!keyStore.isInit) {
830 throw new IllegalArgumentException("KeyStore was not initialized");
832 return new BuilderImpl(keyStore, protectionParameter,
833 null, null, null, null);
837 * Returns a new {@code Builder} that creates a new {@code KeyStore}
838 * based on the provided arguments.
840 * If {@code provider} is {@code null}, all installed providers are
841 * searched, otherwise the key store from the specified provider is
845 * the type of the {@code KeyStore} to be constructed.
847 * the provider of the {@code KeyStore} to be constructed,
848 * maybe {@code null}.
850 * the {@code File} that contains the data for the {@code
852 * @param protectionParameter
853 * the {@code ProtectionParameter} used to protect the stored
855 * @return a new {@code Builder} that creates a new {@code KeyStore}
856 * based on the provided arguments.
857 * @throws NullPointerException
858 * if {@code type, protectionParameter} or {@code file} is
860 * @throws IllegalArgumentException
861 * {@code protectionParameter} not an instance of either
862 * {@code PasswordProtection} or {@code
863 * CallbackHandlerProtection}, {@code file} is not a file or
864 * does not exist at all.
866 public static Builder newInstance(String type, Provider provider,
867 File file, ProtectionParameter protectionParameter) {
868 // check null parameters
870 throw new NullPointerException("type == null");
872 if (protectionParameter == null) {
873 throw new NullPointerException("protectionParameter == null");
876 throw new NullPointerException("file == null");
878 // protection parameter should be PasswordProtection or
879 // CallbackHandlerProtection
880 if (!(protectionParameter instanceof PasswordProtection)
881 && !(protectionParameter instanceof CallbackHandlerProtection)) {
882 throw new IllegalArgumentException("protectionParameter is neither PasswordProtection nor CallbackHandlerProtection instance");
884 // check file parameter
885 if (!file.exists()) {
886 throw new IllegalArgumentException("File does not exist: " + file.getName());
888 if (!file.isFile()) {
889 throw new IllegalArgumentException("Not a regular file: " + file.getName());
891 // create new instance
892 return new BuilderImpl(null, protectionParameter, file,
893 type, provider, AccessController.getContext());
897 * Returns a new {@code Builder} that creates a new {@code KeyStore}
898 * based on the provided arguments.
900 * If {@code provider} is {@code null}, all installed providers are
901 * searched, otherwise the key store from the specified provider is
905 * the type of the {@code KeyStore} to be constructed.
907 * the provider of the {@code KeyStore} to be constructed,
908 * maybe {@code null}.
909 * @param protectionParameter
910 * the {@code ProtectionParameter} used to protect the stored
912 * @return a new {@code Builder} that creates a new {@code KeyStore}
913 * based on the provided arguments.
914 * @throws NullPointerException
915 * if {@code type} or {@code protectionParameter} is {@code
917 * @throws IllegalArgumentException
918 * {@code protectionParameter} not an instance of either
919 * {@code PasswordProtection} or {@code
920 * CallbackHandlerProtection}, {@code file} is not a file or
921 * does not exist at all.
923 public static Builder newInstance(String type, Provider provider,
924 ProtectionParameter protectionParameter) {
926 throw new NullPointerException("type == null");
928 if (protectionParameter == null) {
929 throw new NullPointerException("protectionParameter == null");
931 return new BuilderImpl(null, protectionParameter, null,
932 type, provider, AccessController.getContext());
936 * This class is implementation of abstract class KeyStore.Builder
938 * @author Vera Petrashkova
941 private static class BuilderImpl extends Builder {
942 // Store used KeyStore
943 private KeyStore keyStore;
945 // Store used ProtectionParameter
946 private ProtectionParameter protParameter;
948 // Store used KeyStore type
949 private final String typeForKeyStore;
951 // Store used KeyStore provider
952 private final Provider providerForKeyStore;
954 // Store used file for KeyStore loading
955 private final File fileForLoad;
957 // Store getKeyStore method was invoked or not for KeyStoreBuilder
958 private boolean isGetKeyStore = false;
960 // Store last Exception in getKeyStore()
961 private KeyStoreException lastException;
963 // Store AccessControlContext which is used in getKeyStore() method
964 private final AccessControlContext accControlContext;
967 // Constructor BuilderImpl initializes private fields: keyStore,
968 // protParameter, typeForKeyStore providerForKeyStore fileForLoad,
971 BuilderImpl(KeyStore ks, ProtectionParameter pp, File file,
972 String type, Provider provider, AccessControlContext context) {
977 typeForKeyStore = type;
978 providerForKeyStore = provider;
979 isGetKeyStore = false;
980 lastException = null;
981 accControlContext = context;
985 // Implementation of abstract getKeyStore() method If
986 // KeyStoreBuilder encapsulates KeyStore object then this object is
989 // If KeyStoreBuilder encapsulates KeyStore type and provider then
990 // KeyStore is created using these parameters. If KeyStoreBuilder
991 // encapsulates file and ProtectionParameter then KeyStore data are
992 // loaded from FileInputStream that is created on file. If file is
993 // not defined then KeyStore object is initialized with null
994 // InputStream and null password.
996 // Result KeyStore object is returned.
999 public synchronized KeyStore getKeyStore() throws KeyStoreException {
1000 // If KeyStore was created but in final block some exception was
1002 // then it was stored in lastException variable and will be
1004 // all subsequent calls of this method.
1005 if (lastException != null) {
1006 throw lastException;
1008 if (keyStore != null) {
1009 isGetKeyStore = true;
1015 final char[] passwd;
1017 // get KeyStore instance using type or type and provider
1018 ks = (providerForKeyStore == null ? KeyStore
1019 .getInstance(typeForKeyStore) : KeyStore
1020 .getInstance(typeForKeyStore, providerForKeyStore));
1021 // protection parameter should be PasswordProtection
1022 // or CallbackHandlerProtection
1023 if (protParameter instanceof PasswordProtection) {
1024 passwd = ((PasswordProtection) protParameter)
1026 } else if (protParameter instanceof CallbackHandlerProtection) {
1027 passwd = KeyStoreSpi
1028 .getPasswordFromCallBack(protParameter);
1030 throw new KeyStoreException("protectionParameter is neither PasswordProtection nor CallbackHandlerProtection instance");
1033 // load KeyStore from file
1034 AccessController.doPrivileged(
1035 new PrivilegedExceptionAction<Object>() {
1036 public Object run() throws Exception {
1037 if (fileForLoad != null) {
1038 FileInputStream fis = null;
1040 fis = new FileInputStream(fileForLoad);
1041 ks.load(fis, passwd);
1043 // close file input stream
1049 ks.load(new TmpLSParameter(
1054 }, accControlContext);
1057 isGetKeyStore = true;
1059 } catch (KeyStoreException e) {
1061 throw lastException = e;
1062 } catch (Exception e) {
1063 // Override exception
1064 throw lastException = new KeyStoreException(e);
1069 // This is implementation of abstract method
1070 // getProtectionParameter(String alias)
1072 // Return: ProtectionParameter to get Entry which was saved in
1073 // KeyStore with defined alias
1076 public synchronized ProtectionParameter getProtectionParameter(
1077 String alias) throws KeyStoreException {
1078 if (alias == null) {
1079 throw new NullPointerException("alias == null");
1081 if (!isGetKeyStore) {
1082 throw new IllegalStateException("getKeyStore() was not invoked");
1084 return protParameter;
1089 * Implementation of LoadStoreParameter interface
1091 private static class TmpLSParameter implements LoadStoreParameter {
1093 // Store used protection parameter
1094 private final ProtectionParameter protPar;
1097 * Creates TmpLoadStoreParameter object
1098 * @param protPar protection parameter
1100 public TmpLSParameter(ProtectionParameter protPar) {
1101 this.protPar = protPar;
1105 * This method returns protection parameter
1107 public ProtectionParameter getProtectionParameter() {
1114 * {@code CallbackHandlerProtection} is a {@code ProtectionParameter} that
1115 * encapsulates a {@link CallbackHandler}.
1117 public static class CallbackHandlerProtection implements
1118 ProtectionParameter {
1119 // Store CallbackHandler
1120 private final CallbackHandler callbackHandler;
1123 * Constructs a new instance of {@code CallbackHandlerProtection} with
1124 * the {@code CallbackHandler}.
1127 * the {@code CallbackHandler}.
1128 * @throws NullPointerException
1129 * if {@code handler} is {@code null}.
1131 public CallbackHandlerProtection(CallbackHandler handler) {
1132 if (handler == null) {
1133 throw new NullPointerException("handler == null");
1135 this.callbackHandler = handler;
1139 * Returns the {@code CallbackHandler}.
1141 * @return the {@code CallbackHandler}.
1143 public CallbackHandler getCallbackHandler() {
1144 return callbackHandler;
1149 * {@code Entry} is the common marker interface for a {@code KeyStore}
1152 public static interface Entry {
1156 * {@code LoadStoreParameter} represents a parameter that specifies how a
1157 * {@code KeyStore} can be loaded and stored.
1159 * @see KeyStore#load(LoadStoreParameter)
1160 * @see KeyStore#store(LoadStoreParameter)
1162 public static interface LoadStoreParameter {
1164 * Returns the {@code ProtectionParameter} which is used to protect data
1165 * in the {@code KeyStore}.
1167 * @return the {@code ProtectionParameter} which is used to protect data
1168 * in the {@code KeyStore}, maybe {@code null}.
1170 public ProtectionParameter getProtectionParameter();
1174 * {@code PasswordProtection} is a {@code ProtectionParameter} that protects
1175 * a {@code KeyStore} using a password.
1177 public static class PasswordProtection implements ProtectionParameter,
1181 private char[] password;
1183 private boolean isDestroyed = false;
1186 * Constructs a new instance of {@code PasswordProtection} with a
1187 * password. A copy of the password is stored in the new {@code
1188 * PasswordProtection} object.
1191 * the password, maybe {@code null}.
1193 public PasswordProtection(char[] password) {
1194 if (password != null) {
1195 this.password = password.clone();
1200 * Returns the password.
1202 * @return the password.
1203 * @throws IllegalStateException
1204 * if the password has been destroyed.
1206 public synchronized char[] getPassword() {
1208 throw new IllegalStateException("Password was destroyed");
1214 * Destroys / invalidates the password.
1216 * @throws DestroyFailedException
1217 * if the password could not be invalidated.
1219 public synchronized void destroy() throws DestroyFailedException {
1221 if (password != null) {
1222 Arrays.fill(password, '\u0000');
1228 * Indicates whether the password is invalidated.
1230 * @return {@code true} if the password is invalidated, {@code false}
1233 public synchronized boolean isDestroyed() {
1239 * {@code ProtectionParameter} is a marker interface for protection
1240 * parameters. A protection parameter is used to protect the content of a
1243 public static interface ProtectionParameter {
1247 * {@code PrivateKeyEntry} represents a {@code KeyStore} entry that
1248 * holds a private key.
1250 public static final class PrivateKeyEntry implements Entry {
1251 // Store Certificate chain
1252 private Certificate[] chain;
1255 private PrivateKey privateKey;
1258 * Constructs a new instance of {@code PrivateKeyEntry} with the given
1259 * {@code PrivateKey} and the provided certificate chain.
1264 * the ordered certificate chain with the certificate
1265 * corresponding to the private key at index 0.
1266 * @throws NullPointerException
1267 * if {@code privateKey} or {@code chain} is {@code null}.
1268 * @throws IllegalArgumentException
1269 * if {@code chain.length == 0}, the algorithm of the
1270 * private key does not match the algorithm of the public
1271 * key of the first certificate or the certificates are not
1272 * all of the same type.
1274 public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) {
1275 if (privateKey == null) {
1276 throw new NullPointerException("privateKey == null");
1278 if (chain == null) {
1279 throw new NullPointerException("chain == null");
1282 if (chain.length == 0) {
1283 throw new IllegalArgumentException("chain.length == 0");
1285 // Match algorithm of private key and algorithm of public key from
1286 // the end certificate
1287 String s = chain[0].getType();
1288 if (!(chain[0].getPublicKey().getAlgorithm()).equals(privateKey.getAlgorithm())) {
1289 throw new IllegalArgumentException("Algorithm of private key does not match " +
1290 "algorithm of public key in end certificate of entry (with index number: 0)");
1292 // Match certificate types
1293 for (int i = 1; i < chain.length; i++) {
1294 if (!s.equals(chain[i].getType())) {
1295 throw new IllegalArgumentException("Certificates from the given chain have different types");
1298 // clone chain - this.chain = (Certificate[])chain.clone();
1299 boolean isAllX509Certificates = true;
1300 // assert chain length > 0
1301 for(Certificate cert: chain){
1302 if(!(cert instanceof X509Certificate)){
1303 isAllX509Certificates = false;
1308 if(isAllX509Certificates){
1309 this.chain = new X509Certificate[chain.length];
1311 this.chain = new Certificate[chain.length];
1313 System.arraycopy(chain, 0, this.chain, 0, chain.length);
1314 this.privateKey = privateKey;
1318 * Returns the private key.
1320 * @return the private key.
1322 public PrivateKey getPrivateKey() {
1327 * Returns the certificate chain.
1329 * @return the certificate chain.
1331 public Certificate[] getCertificateChain() {
1332 return chain.clone();
1336 * Returns the certificate corresponding to the private key.
1338 * @return the certificate corresponding to the private key.
1340 public Certificate getCertificate() {
1345 * Returns a string containing a concise, human-readable description of
1346 * this {@code PrivateKeyEntry}.
1348 * @return a printable representation for this {@code PrivateKeyEntry}.
1351 public String toString() {
1352 StringBuilder sb = new StringBuilder(
1353 "PrivateKeyEntry: number of elements in certificate chain is ");
1354 sb.append(Integer.toString(chain.length));
1356 for (int i = 0; i < chain.length; i++) {
1357 sb.append(chain[i].toString());
1360 return sb.toString();
1365 * {@code SecretKeyEntry} represents a {@code KeyStore} entry that
1366 * holds a secret key.
1368 public static final class SecretKeyEntry implements Entry {
1371 private final SecretKey secretKey;
1374 * Constructs a new instance of {@code SecretKeyEntry} with the given
1375 * {@code SecretKey}.
1379 * @throws NullPointerException
1380 * if {@code secretKey} is {@code null}.
1382 public SecretKeyEntry(SecretKey secretKey) {
1383 if (secretKey == null) {
1384 throw new NullPointerException("secretKey == null");
1386 this.secretKey = secretKey;
1390 * Returns the secret key.
1392 * @return the secret key.
1394 public SecretKey getSecretKey() {
1399 * Returns a string containing a concise, human-readable description of
1400 * this {@code SecretKeyEntry}.
1402 * @return a printable representation for this {@code
1406 public String toString() {
1407 StringBuilder sb = new StringBuilder("SecretKeyEntry: algorithm - ");
1408 sb.append(secretKey.getAlgorithm());
1409 return sb.toString();
1414 * {@code TrustedCertificateEntry} represents a {@code KeyStore} entry that
1415 * holds a trusted certificate.
1417 public static final class TrustedCertificateEntry implements Entry {
1419 // Store trusted Certificate
1420 private final Certificate trustCertificate;
1423 * Constructs a new instance of {@code TrustedCertificateEntry} with the
1424 * given {@code Certificate}.
1426 * @param trustCertificate
1427 * the trusted certificate.
1428 * @throws NullPointerException
1429 * if {@code trustCertificate} is {@code null}.
1431 public TrustedCertificateEntry(Certificate trustCertificate) {
1432 if (trustCertificate == null) {
1433 throw new NullPointerException("trustCertificate == null");
1435 this.trustCertificate = trustCertificate;
1439 * Returns the trusted certificate.
1441 * @return the trusted certificate.
1443 public Certificate getTrustedCertificate() {
1444 return trustCertificate;
1448 * Returns a string containing a concise, human-readable description of
1449 * this {@code TrustedCertificateEntry}.
1451 * @return a printable representation for this {@code
1452 * TrustedCertificateEntry}.
1455 public String toString() {
1456 return "Trusted certificate entry:\n" + trustCertificate;