| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package java.security; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.security.cert.Certificate; |
| import java.security.cert.CertificateException; |
| import java.security.cert.X509Certificate; |
| import java.util.Arrays; |
| import java.util.Date; |
| import java.util.Enumeration; |
| import javax.crypto.SecretKey; |
| import javax.security.auth.DestroyFailedException; |
| import javax.security.auth.Destroyable; |
| import javax.security.auth.callback.CallbackHandler; |
| import org.apache.harmony.security.fortress.Engine; |
| |
| /** |
| * {@code KeyStore} is responsible for maintaining cryptographic keys and their |
| * owners. |
| * <p> |
| * The type of the system key store can be changed by setting the {@code |
| * 'keystore.type'} property in the file named {@code |
| * JAVA_HOME/lib/security/java.security}. |
| * |
| * @see Certificate |
| * @see PrivateKey |
| */ |
| public class KeyStore { |
| |
| // Store KeyStore SERVICE name |
| private static final String SERVICE = "KeyStore"; |
| |
| // Used to access common engine functionality |
| private static Engine engine = new Engine(SERVICE); |
| |
| // Store KeyStore property name |
| private static final String PROPERTYNAME = "keystore.type"; |
| |
| // Store default KeyStore type |
| private static final String DEFAULT_KEYSTORE_TYPE = "jks"; |
| |
| // Store KeyStore state (initialized or not) |
| private boolean isInit; |
| |
| // Store used KeyStoreSpi |
| private final KeyStoreSpi implSpi; |
| |
| // Store used provider |
| private final Provider provider; |
| |
| // Store used type |
| private final String type; |
| |
| /** |
| * Constructs a new instance of {@code KeyStore} with the given arguments. |
| * |
| * @param keyStoreSpi |
| * the concrete key store. |
| * @param provider |
| * the provider. |
| * @param type |
| * the type of the {@code KeyStore} to be constructed. |
| */ |
| protected KeyStore(KeyStoreSpi keyStoreSpi, Provider provider, String type) { |
| this.type = type; |
| this.provider = provider; |
| this.implSpi = keyStoreSpi; |
| isInit = false; |
| } |
| |
| /** |
| * Throws the standard "keystore not initialized" exception. |
| */ |
| private static void throwNotInitialized() throws KeyStoreException { |
| throw new KeyStoreException("KeyStore was not initialized"); |
| } |
| |
| /** |
| * Returns a new instance of {@code KeyStore} with the specified type. |
| * |
| * @param type |
| * the type of the returned {@code KeyStore}. |
| * @return a new instance of {@code KeyStore} with the specified type. |
| * @throws KeyStoreException |
| * if an error occurred during the creation of the new {@code |
| * KeyStore}. |
| * @throws NullPointerException if {@code type == null} |
| * @see #getDefaultType |
| */ |
| public static KeyStore getInstance(String type) throws KeyStoreException { |
| if (type == null) { |
| throw new NullPointerException(); |
| } |
| synchronized (engine) { |
| try { |
| engine.getInstance(type, null); |
| return new KeyStore((KeyStoreSpi) engine.spi, engine.provider, type); |
| } catch (NoSuchAlgorithmException e) { |
| throw new KeyStoreException(e.getMessage()); |
| } |
| } |
| } |
| |
| /** |
| * Returns a new instance of {@code KeyStore} from the specified provider |
| * with the given type. |
| * |
| * @param type |
| * the type of the returned {@code KeyStore}. |
| * @param provider |
| * name of the provider of the {@code KeyStore}. |
| * @return a new instance of {@code KeyStore} from the specified provider |
| * with the given type. |
| * @throws KeyStoreException |
| * if an error occurred during the creation of the new {@code |
| * KeyStore}. |
| * @throws NoSuchProviderException |
| * if the specified provider is not available. |
| * @throws IllegalArgumentException if {@code provider == null || provider.isEmpty()} |
| * @throws NullPointerException |
| * if {@code type} is {@code null} (instead of |
| * NoSuchAlgorithmException) as in 1.4 release |
| * @see #getDefaultType |
| */ |
| public static KeyStore getInstance(String type, String provider) |
| throws KeyStoreException, NoSuchProviderException { |
| if (provider == null || provider.isEmpty()) { |
| throw new IllegalArgumentException(); |
| } |
| Provider impProvider = Security.getProvider(provider); |
| if (impProvider == null) { |
| throw new NoSuchProviderException(provider); |
| } |
| try { |
| return getInstance(type, impProvider); |
| } catch (Exception e) { |
| throw new KeyStoreException(e.getMessage(), e); |
| } |
| } |
| |
| /** |
| * Returns a new instance of {@code KeyStore} from the specified provider |
| * with the given type. |
| * |
| * @param type |
| * the type of the returned {@code KeyStore}. |
| * @param provider |
| * the provider of the {@code KeyStore}. |
| * @return a new instance of {@code KeyStore} from the specified provider |
| * with the given type. |
| * @throws KeyStoreException |
| * if an error occurred during the creation of the new {@code |
| * KeyStore}. |
| * @throws IllegalArgumentException |
| * if {@code provider} is {@code null} or the empty string. |
| * @throws NullPointerException if {@code type == null} (instead of |
| * NoSuchAlgorithmException) as in 1.4 release |
| * @see #getDefaultType |
| */ |
| public static KeyStore getInstance(String type, Provider provider) |
| throws KeyStoreException { |
| // check parameters |
| if (provider == null) { |
| throw new IllegalArgumentException(); |
| } |
| if (type == null) { |
| throw new NullPointerException(); |
| } |
| // return KeyStore instance |
| synchronized (engine) { |
| try { |
| engine.getInstance(type, provider, null); |
| return new KeyStore((KeyStoreSpi) engine.spi, provider, type); |
| } catch (Exception e) { |
| // override exception |
| throw new KeyStoreException(e.getMessage()); |
| } |
| } |
| } |
| |
| /** |
| * Returns the default type for {@code KeyStore} instances. |
| * <p> |
| * The default is specified in the {@code 'keystore.type'} property in the |
| * file named {@code JAVA_HOME/lib/security/java.security}. If this property |
| * is not set, {@code "jks"} will be used. |
| * |
| * @return the default type for {@code KeyStore} instances |
| */ |
| public static final String getDefaultType() { |
| String dt = AccessController.doPrivileged( |
| new PrivilegedAction<String>() { |
| public String run() { |
| return Security.getProperty(PROPERTYNAME); |
| } |
| } |
| ); |
| return (dt == null ? DEFAULT_KEYSTORE_TYPE : dt); |
| } |
| |
| /** |
| * Returns the provider associated with this {@code KeyStore}. |
| * |
| * @return the provider associated with this {@code KeyStore}. |
| */ |
| public final Provider getProvider() { |
| return provider; |
| } |
| |
| /** |
| * Returns the type of this {@code KeyStore}. |
| * |
| * @return the type of this {@code KeyStore}. |
| */ |
| public final String getType() { |
| return type; |
| } |
| |
| /** |
| * Returns the key with the given alias, using the password to recover the |
| * key from the store. |
| * |
| * @param alias |
| * the alias for the entry. |
| * @param password |
| * the password used to recover the key. |
| * @return the key with the specified alias, or {@code null} if the |
| * specified alias is not bound to an entry. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| * @throws NoSuchAlgorithmException |
| * if the algorithm for recovering the key is not available. |
| * @throws UnrecoverableKeyException |
| * if the key can not be recovered. |
| */ |
| public final Key getKey(String alias, char[] password) |
| throws KeyStoreException, NoSuchAlgorithmException, |
| UnrecoverableKeyException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| return implSpi.engineGetKey(alias, password); |
| } |
| |
| /** |
| * Returns the certificate chain for the entry with the given alias. |
| * |
| * @param alias |
| * the alias for the entry. |
| * @return the certificate chain for the entry with the given alias, or |
| * {@code null} if the specified alias is not bound to an entry. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| */ |
| public final Certificate[] getCertificateChain(String alias) |
| throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| return implSpi.engineGetCertificateChain(alias); |
| } |
| |
| /** |
| * Returns the trusted certificate for the entry with the given alias. |
| * |
| * @param alias |
| * the alias for the entry. |
| * @return the trusted certificate for the entry with the given alias, or |
| * {@code null} if the specified alias is not bound to an entry. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| */ |
| public final Certificate getCertificate(String alias) |
| throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| return implSpi.engineGetCertificate(alias); |
| } |
| |
| /** |
| * Returns the creation date of the entry with the given alias. |
| * |
| * @param alias |
| * the alias for the entry. |
| * @return the creation date, or {@code null} if the specified alias is not |
| * bound to an entry. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| */ |
| public final Date getCreationDate(String alias) throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| return implSpi.engineGetCreationDate(alias); |
| } |
| |
| /** |
| * Associates the given alias with the key, password and certificate chain. |
| * <p> |
| * If the specified alias already exists, it will be reassigned. |
| * |
| * @param alias |
| * the alias for the key. |
| * @param key |
| * the key. |
| * @param password |
| * the password. |
| * @param chain |
| * the certificate chain. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| * @throws IllegalArgumentException |
| * if {@code key} is a {@code PrivateKey} and {@code chain} does |
| * not contain any certificates. |
| * @throws NullPointerException |
| * if {@code alias} is {@code null}. |
| */ |
| public final void setKeyEntry(String alias, Key key, char[] password, |
| Certificate[] chain) throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| |
| // Certificate chain is required for PrivateKey |
| if (null != key && key instanceof PrivateKey && (chain == null || chain.length == 0)) { |
| throw new IllegalArgumentException("Certificate chain is not defined for Private key"); |
| } |
| implSpi.engineSetKeyEntry(alias, key, password, chain); |
| } |
| |
| /** |
| * Associates the given alias with a key and a certificate chain. |
| * <p> |
| * If the specified alias already exists, it will be reassigned. |
| * <p> |
| * If this {@code KeyStore} is of type {@code "jks"}, {@code key} must be |
| * encoded conform to the PKS#8 standard as an |
| * {@link javax.crypto.EncryptedPrivateKeyInfo}. |
| * |
| * @param alias |
| * the alias for the key. |
| * @param key |
| * the key in an encoded format. |
| * @param chain |
| * the certificate chain. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized or if {@code key} |
| * is null. |
| * @throws IllegalArgumentException |
| * if {@code key} is a {@code PrivateKey} and {@code chain} |
| * does. |
| * @throws NullPointerException |
| * if {@code alias} is {@code null}. |
| */ |
| public final void setKeyEntry(String alias, byte[] key, Certificate[] chain) |
| throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| implSpi.engineSetKeyEntry(alias, key, chain); |
| } |
| |
| /** |
| * Associates the given alias with a certificate. |
| * <p> |
| * If the specified alias already exists, it will be reassigned. |
| * |
| * @param alias |
| * the alias for the certificate. |
| * @param cert |
| * the certificate. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized, or an existing |
| * alias is not associated to an entry containing a trusted |
| * certificate, or this method fails for any other reason. |
| * @throws NullPointerException |
| * if {@code alias} is {@code null}. |
| */ |
| public final void setCertificateEntry(String alias, Certificate cert) |
| throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| implSpi.engineSetCertificateEntry(alias, cert); |
| } |
| |
| /** |
| * Deletes the entry identified with the given alias from this {@code |
| * KeyStore}. |
| * |
| * @param alias |
| * the alias for the entry. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized, or if the entry |
| * can not be deleted. |
| */ |
| public final void deleteEntry(String alias) throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| implSpi.engineDeleteEntry(alias); |
| } |
| |
| /** |
| * Returns an {@code Enumeration} over all alias names stored in this |
| * {@code KeyStore}. |
| * |
| * @return an {@code Enumeration} over all alias names stored in this |
| * {@code KeyStore}. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| */ |
| public final Enumeration<String> aliases() throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| return implSpi.engineAliases(); |
| } |
| |
| /** |
| * Indicates whether the given alias is present in this {@code KeyStore}. |
| * |
| * @param alias |
| * the alias of an entry. |
| * @return {@code true} if the alias exists, {@code false} otherwise. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| */ |
| public final boolean containsAlias(String alias) throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| return implSpi.engineContainsAlias(alias); |
| } |
| |
| /** |
| * Returns the number of entries stored in this {@code KeyStore}. |
| * |
| * @return the number of entries stored in this {@code KeyStore}. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| */ |
| public final int size() throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| return implSpi.engineSize(); |
| } |
| |
| /** |
| * Indicates whether the specified alias is associated with either a |
| * {@link PrivateKeyEntry} or a {@link SecretKeyEntry}. |
| * |
| * @param alias |
| * the alias of an entry. |
| * @return {@code true} if the given alias is associated with a key entry. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| */ |
| public final boolean isKeyEntry(String alias) throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| return implSpi.engineIsKeyEntry(alias); |
| } |
| |
| /** |
| * Indicates whether the specified alias is associated with a |
| * {@link TrustedCertificateEntry}. |
| * |
| * @param alias |
| * the alias of an entry. |
| * @return {@code true} if the given alias is associated with a certificate |
| * entry. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| */ |
| public final boolean isCertificateEntry(String alias) |
| throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| return implSpi.engineIsCertificateEntry(alias); |
| } |
| |
| /** |
| * Returns the alias associated with the first entry whose certificate |
| * matches the specified certificate. |
| * |
| * @param cert |
| * the certificate to find the associated entry's alias for. |
| * @return the alias or {@code null} if no entry with the specified |
| * certificate can be found. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| */ |
| public final String getCertificateAlias(Certificate cert) |
| throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| return implSpi.engineGetCertificateAlias(cert); |
| } |
| |
| /** |
| * Writes this {@code KeyStore} to the specified {@code OutputStream}. The |
| * data written to the {@code OutputStream} is protected by the specified |
| * password. |
| * |
| * @param stream |
| * the {@code OutputStream} to write the store's data to. |
| * @param password |
| * the password to protect the data. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| * @throws IOException |
| * if a problem occurred while writing to the stream. |
| * @throws NoSuchAlgorithmException |
| * if the required algorithm is not available. |
| * @throws CertificateException |
| * if an exception occurred while storing the certificates of |
| * this {@code KeyStore}. |
| */ |
| public final void store(OutputStream stream, char[] password) |
| throws KeyStoreException, IOException, NoSuchAlgorithmException, |
| CertificateException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| |
| //Just delegate stream and password to implSpi |
| implSpi.engineStore(stream, password); |
| } |
| |
| /** |
| * Stores this {@code KeyStore} using the specified {@code |
| * LoadStoreParameter}. |
| * |
| * @param param |
| * the {@code LoadStoreParameter} that specifies how to store |
| * this {@code KeyStore}, maybe {@code null}. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| * @throws IOException |
| * if a problem occurred while writing to the stream. |
| * @throws NoSuchAlgorithmException |
| * if the required algorithm is not available. |
| * @throws CertificateException |
| * if an exception occurred while storing the certificates of |
| * this {@code KeyStore}. |
| * @throws IllegalArgumentException |
| * if the given {@link LoadStoreParameter} is not recognized. |
| */ |
| public final void store(LoadStoreParameter param) throws KeyStoreException, |
| IOException, NoSuchAlgorithmException, CertificateException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| implSpi.engineStore(param); |
| } |
| |
| /** |
| * Initializes this {@code KeyStore} from the provided {@code InputStream}. |
| * Pass {@code null} as the {@code stream} argument to initialize an empty |
| * {@code KeyStore} or to initialize a {@code KeyStore} which does not rely |
| * on an {@code InputStream}. This {@code KeyStore} utilizes the given |
| * password to verify the stored data. |
| * |
| * @param stream |
| * the {@code InputStream} to load this {@code KeyStore}'s data |
| * from or {@code null}. |
| * @param password |
| * the password to verify the stored data, maybe {@code null}. |
| * @throws IOException |
| * if a problem occurred while reading from the stream. |
| * @throws NoSuchAlgorithmException |
| * if the required algorithm is not available. |
| * @throws CertificateException |
| * if an exception occurred while loading the certificates of |
| * this {@code KeyStore}. |
| */ |
| public final void load(InputStream stream, char[] password) |
| throws IOException, NoSuchAlgorithmException, CertificateException { |
| implSpi.engineLoad(stream, password); |
| isInit = true; |
| } |
| |
| /** |
| * Loads this {@code KeyStore} using the specified {@code |
| * LoadStoreParameter}. |
| * |
| * @param param |
| * the {@code LoadStoreParameter} that specifies how to load this |
| * {@code KeyStore}, maybe {@code null}. |
| * @throws IOException |
| * if a problem occurred while reading from the stream. |
| * @throws NoSuchAlgorithmException |
| * if the required algorithm is not available. |
| * @throws CertificateException |
| * if an exception occurred while loading the certificates of |
| * this {@code KeyStore}. |
| * @throws IllegalArgumentException |
| * if the given {@link LoadStoreParameter} is not recognized. |
| */ |
| public final void load(LoadStoreParameter param) throws IOException, |
| NoSuchAlgorithmException, CertificateException { |
| implSpi.engineLoad(param); |
| isInit = true; |
| } |
| |
| /** |
| * Returns the {@code Entry} with the given alias, using the specified |
| * {@code ProtectionParameter}. |
| * |
| * @param alias |
| * the alias of the requested entry. |
| * @param param |
| * the {@code ProtectionParameter} used to protect the requested |
| * entry, maybe {@code null}. |
| * @return he {@code Entry} with the given alias, using the specified |
| * {@code ProtectionParameter}. |
| * @throws NoSuchAlgorithmException |
| * if the required algorithm is not available. |
| * @throws UnrecoverableEntryException |
| * if the entry can not be recovered. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| * @throws NullPointerException |
| * if {@code alias} is {@code null}. |
| */ |
| public final Entry getEntry(String alias, ProtectionParameter param) |
| throws NoSuchAlgorithmException, UnrecoverableEntryException, |
| KeyStoreException { |
| if (alias == null) { |
| throw new NullPointerException("alias == null"); |
| } |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| return implSpi.engineGetEntry(alias, param); |
| } |
| |
| /** |
| * Stores the given {@code Entry} in this {@code KeyStore} and associates |
| * the entry with the given {@code alias}. The entry is protected by the |
| * specified {@code ProtectionParameter}. |
| * <p> |
| * If the specified alias already exists, it will be reassigned. |
| * |
| * @param alias |
| * the alias for the entry. |
| * @param entry |
| * the entry to store. |
| * @param param |
| * the {@code ProtectionParameter} to protect the entry. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| * @throws NullPointerException |
| * if {@code alias} is {@code null} or {@code entry} is {@code |
| * null}. |
| */ |
| public final void setEntry(String alias, Entry entry, |
| ProtectionParameter param) throws KeyStoreException { |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| if (alias == null) { |
| throw new NullPointerException("alias == null"); |
| } |
| if (entry == null) { |
| throw new NullPointerException("entry == null"); |
| } |
| implSpi.engineSetEntry(alias, entry, param); |
| } |
| |
| /** |
| * Indicates whether the entry for the given alias is assignable to the |
| * provided {@code Class}. |
| * |
| * @param alias |
| * the alias for the entry. |
| * @param entryClass |
| * the type of the entry. |
| * @return {@code true} if the {@code Entry} for the alias is assignable to |
| * the specified {@code entryClass}. |
| * @throws KeyStoreException |
| * if this {@code KeyStore} is not initialized. |
| */ |
| public final boolean entryInstanceOf(String alias, |
| Class<? extends KeyStore.Entry> entryClass) |
| throws KeyStoreException { |
| if (alias == null) { |
| throw new NullPointerException("alias == null"); |
| } |
| if (entryClass == null) { |
| throw new NullPointerException("entryClass == null"); |
| } |
| |
| if (!isInit) { |
| // BEGIN android-changed |
| throwNotInitialized(); |
| // END android-changed |
| } |
| return implSpi.engineEntryInstanceOf(alias, entryClass); |
| } |
| |
| /** |
| * {@code Builder} is used to construct new instances of {@code KeyStore}. |
| */ |
| public abstract static class Builder { |
| /** |
| * Constructs a new instance of {@code Builder}. |
| */ |
| protected Builder() { |
| } |
| |
| /** |
| * Returns the {@code KeyStore} created by this {@code Builder}. |
| * |
| * @return the {@code KeyStore} created by this {@code Builder}. |
| * @throws KeyStoreException |
| * if an error occurred during construction. |
| */ |
| public abstract KeyStore getKeyStore() throws KeyStoreException; |
| |
| /** |
| * Returns the {@code ProtectionParameter} to be used when a {@code |
| * Entry} with the specified alias is requested. Before this method is |
| * invoked, {@link #getKeyStore()} must be called. |
| * |
| * @param alias |
| * the alias for the entry. |
| * @return the {@code ProtectionParameter} to be used when a {@code |
| * Entry} with the specified alias is requested. |
| * @throws KeyStoreException |
| * if an error occurred during the lookup for the protection |
| * parameter. |
| * @throws IllegalStateException |
| * if {@link #getKeyStore()} is not called prior the |
| * invocation of this method. |
| * @throws NullPointerException |
| * if {@code alias} is {@code null}. |
| */ |
| public abstract ProtectionParameter getProtectionParameter(String alias) |
| throws KeyStoreException; |
| |
| /** |
| * Returns a new {@code Builder} that holds the given {@code KeyStore} |
| * and the given {@code ProtectionParameter}. |
| * |
| * @param keyStore |
| * the {@code KeyStore} to be held. |
| * @param protectionParameter |
| * the {@code ProtectionParameter} to be held. |
| * @return a new instance of {@code Builder} that holds the specified |
| * {@code KeyStore} and the specified {@code |
| * ProtectionParameter}. |
| * @throws NullPointerException |
| * if {@code keyStore} or {@code protectionParameter} is |
| * {@code null}. |
| * @throws IllegalArgumentException |
| * if the given {@code KeyStore} is not initialized. |
| */ |
| public static Builder newInstance(KeyStore keyStore, |
| ProtectionParameter protectionParameter) { |
| if (keyStore == null) { |
| throw new NullPointerException("keyStore == null"); |
| } |
| if (protectionParameter == null) { |
| throw new NullPointerException("protectionParameter == null"); |
| } |
| if (!keyStore.isInit) { |
| throw new IllegalArgumentException("KeyStore was not initialized"); |
| } |
| return new BuilderImpl(keyStore, protectionParameter, |
| null, null, null, null); |
| } |
| |
| /** |
| * Returns a new {@code Builder} that creates a new {@code KeyStore} |
| * based on the provided arguments. |
| * <p> |
| * If {@code provider} is {@code null}, all installed providers are |
| * searched, otherwise the key store from the specified provider is |
| * used. |
| * |
| * @param type |
| * the type of the {@code KeyStore} to be constructed. |
| * @param provider |
| * the provider of the {@code KeyStore} to be constructed, |
| * maybe {@code null}. |
| * @param file |
| * the {@code File} that contains the data for the {@code |
| * KeyStore}. |
| * @param protectionParameter |
| * the {@code ProtectionParameter} used to protect the stored |
| * keys. |
| * @return a new {@code Builder} that creates a new {@code KeyStore} |
| * based on the provided arguments. |
| * @throws NullPointerException |
| * if {@code type, protectionParameter} or {@code file} is |
| * {@code null}. |
| * @throws IllegalArgumentException |
| * {@code protectionParameter} not an instance of either |
| * {@code PasswordProtection} or {@code |
| * CallbackHandlerProtection}, {@code file} is not a file or |
| * does not exist at all. |
| */ |
| public static Builder newInstance(String type, Provider provider, |
| File file, ProtectionParameter protectionParameter) { |
| // check null parameters |
| if (type == null) { |
| throw new NullPointerException("type == null"); |
| } |
| if (protectionParameter == null) { |
| throw new NullPointerException("protectionParameter == null"); |
| } |
| if (file == null) { |
| throw new NullPointerException("file == null"); |
| } |
| // protection parameter should be PasswordProtection or |
| // CallbackHandlerProtection |
| if (!(protectionParameter instanceof PasswordProtection) |
| && !(protectionParameter instanceof CallbackHandlerProtection)) { |
| throw new IllegalArgumentException("protectionParameter is neither PasswordProtection nor CallbackHandlerProtection instance"); |
| } |
| // check file parameter |
| if (!file.exists()) { |
| throw new IllegalArgumentException("File does not exist: " + file.getName()); |
| } |
| if (!file.isFile()) { |
| throw new IllegalArgumentException("Not a regular file: " + file.getName()); |
| } |
| // create new instance |
| return new BuilderImpl(null, protectionParameter, file, |
| type, provider, AccessController.getContext()); |
| } |
| |
| /** |
| * Returns a new {@code Builder} that creates a new {@code KeyStore} |
| * based on the provided arguments. |
| * <p> |
| * If {@code provider} is {@code null}, all installed providers are |
| * searched, otherwise the key store from the specified provider is |
| * used. |
| * |
| * @param type |
| * the type of the {@code KeyStore} to be constructed. |
| * @param provider |
| * the provider of the {@code KeyStore} to be constructed, |
| * maybe {@code null}. |
| * @param protectionParameter |
| * the {@code ProtectionParameter} used to protect the stored |
| * keys. |
| * @return a new {@code Builder} that creates a new {@code KeyStore} |
| * based on the provided arguments. |
| * @throws NullPointerException |
| * if {@code type} or {@code protectionParameter} is {@code |
| * null}. |
| * @throws IllegalArgumentException |
| * {@code protectionParameter} not an instance of either |
| * {@code PasswordProtection} or {@code |
| * CallbackHandlerProtection}, {@code file} is not a file or |
| * does not exist at all. |
| */ |
| public static Builder newInstance(String type, Provider provider, |
| ProtectionParameter protectionParameter) { |
| if (type == null) { |
| throw new NullPointerException("type == null"); |
| } |
| if (protectionParameter == null) { |
| throw new NullPointerException("protectionParameter == null"); |
| } |
| return new BuilderImpl(null, protectionParameter, null, |
| type, provider, AccessController.getContext()); |
| } |
| |
| /* |
| * This class is implementation of abstract class KeyStore.Builder |
| * |
| * @author Vera Petrashkova |
| * |
| */ |
| private static class BuilderImpl extends Builder { |
| // Store used KeyStore |
| private KeyStore keyStore; |
| |
| // Store used ProtectionParameter |
| private ProtectionParameter protParameter; |
| |
| // Store used KeyStore type |
| private final String typeForKeyStore; |
| |
| // Store used KeyStore provider |
| private final Provider providerForKeyStore; |
| |
| // Store used file for KeyStore loading |
| private final File fileForLoad; |
| |
| // Store getKeyStore method was invoked or not for KeyStoreBuilder |
| private boolean isGetKeyStore = false; |
| |
| // Store last Exception in getKeyStore() |
| private KeyStoreException lastException; |
| |
| // Store AccessControlContext which is used in getKeyStore() method |
| private final AccessControlContext accControlContext; |
| |
| // |
| // Constructor BuilderImpl initializes private fields: keyStore, |
| // protParameter, typeForKeyStore providerForKeyStore fileForLoad, |
| // isGetKeyStore |
| // |
| BuilderImpl(KeyStore ks, ProtectionParameter pp, File file, |
| String type, Provider provider, AccessControlContext context) { |
| super(); |
| keyStore = ks; |
| protParameter = pp; |
| fileForLoad = file; |
| typeForKeyStore = type; |
| providerForKeyStore = provider; |
| isGetKeyStore = false; |
| lastException = null; |
| accControlContext = context; |
| } |
| |
| // |
| // Implementation of abstract getKeyStore() method If |
| // KeyStoreBuilder encapsulates KeyStore object then this object is |
| // returned |
| // |
| // If KeyStoreBuilder encapsulates KeyStore type and provider then |
| // KeyStore is created using these parameters. If KeyStoreBuilder |
| // encapsulates file and ProtectionParameter then KeyStore data are |
| // loaded from FileInputStream that is created on file. If file is |
| // not defined then KeyStore object is initialized with null |
| // InputStream and null password. |
| // |
| // Result KeyStore object is returned. |
| // |
| @Override |
| public synchronized KeyStore getKeyStore() throws KeyStoreException { |
| // If KeyStore was created but in final block some exception was |
| // thrown |
| // then it was stored in lastException variable and will be |
| // thrown |
| // all subsequent calls of this method. |
| if (lastException != null) { |
| throw lastException; |
| } |
| if (keyStore != null) { |
| isGetKeyStore = true; |
| return keyStore; |
| } |
| |
| try { |
| final KeyStore ks; |
| final char[] passwd; |
| |
| // get KeyStore instance using type or type and provider |
| ks = (providerForKeyStore == null ? KeyStore |
| .getInstance(typeForKeyStore) : KeyStore |
| .getInstance(typeForKeyStore, providerForKeyStore)); |
| // protection parameter should be PasswordProtection |
| // or CallbackHandlerProtection |
| if (protParameter instanceof PasswordProtection) { |
| passwd = ((PasswordProtection) protParameter) |
| .getPassword(); |
| } else if (protParameter instanceof CallbackHandlerProtection) { |
| passwd = KeyStoreSpi |
| .getPasswordFromCallBack(protParameter); |
| } else { |
| throw new KeyStoreException("protectionParameter is neither PasswordProtection nor CallbackHandlerProtection instance"); |
| } |
| |
| // load KeyStore from file |
| AccessController.doPrivileged( |
| new PrivilegedExceptionAction<Object>() { |
| public Object run() throws Exception { |
| if (fileForLoad != null) { |
| FileInputStream fis = null; |
| try { |
| fis = new FileInputStream(fileForLoad); |
| ks.load(fis, passwd); |
| } finally { |
| // close file input stream |
| if( fis != null ) { |
| fis.close(); |
| } |
| } |
| } else { |
| ks.load(new TmpLSParameter( |
| protParameter)); |
| } |
| return null; |
| } |
| }, accControlContext); |
| |
| |
| isGetKeyStore = true; |
| return ks; |
| } catch (KeyStoreException e) { |
| // Store exception |
| throw lastException = e; |
| } catch (Exception e) { |
| // Override exception |
| throw lastException = new KeyStoreException(e); |
| } |
| } |
| |
| // |
| // This is implementation of abstract method |
| // getProtectionParameter(String alias) |
| // |
| // Return: ProtectionParameter to get Entry which was saved in |
| // KeyStore with defined alias |
| // |
| @Override |
| public synchronized ProtectionParameter getProtectionParameter( |
| String alias) throws KeyStoreException { |
| if (alias == null) { |
| throw new NullPointerException("alias == null"); |
| } |
| if (!isGetKeyStore) { |
| throw new IllegalStateException("getKeyStore() was not invoked"); |
| } |
| return protParameter; |
| } |
| } |
| |
| /* |
| * Implementation of LoadStoreParameter interface |
| */ |
| private static class TmpLSParameter implements LoadStoreParameter { |
| |
| // Store used protection parameter |
| private final ProtectionParameter protPar; |
| |
| /** |
| * Creates TmpLoadStoreParameter object |
| * @param protPar protection parameter |
| */ |
| public TmpLSParameter(ProtectionParameter protPar) { |
| this.protPar = protPar; |
| } |
| |
| /** |
| * This method returns protection parameter |
| */ |
| public ProtectionParameter getProtectionParameter() { |
| return protPar; |
| } |
| } |
| } |
| |
| /** |
| * {@code CallbackHandlerProtection} is a {@code ProtectionParameter} that |
| * encapsulates a {@link CallbackHandler}. |
| */ |
| public static class CallbackHandlerProtection implements |
| ProtectionParameter { |
| // Store CallbackHandler |
| private final CallbackHandler callbackHandler; |
| |
| /** |
| * Constructs a new instance of {@code CallbackHandlerProtection} with |
| * the {@code CallbackHandler}. |
| * |
| * @param handler |
| * the {@code CallbackHandler}. |
| * @throws NullPointerException |
| * if {@code handler} is {@code null}. |
| */ |
| public CallbackHandlerProtection(CallbackHandler handler) { |
| if (handler == null) { |
| throw new NullPointerException("handler == null"); |
| } |
| this.callbackHandler = handler; |
| } |
| |
| /** |
| * Returns the {@code CallbackHandler}. |
| * |
| * @return the {@code CallbackHandler}. |
| */ |
| public CallbackHandler getCallbackHandler() { |
| return callbackHandler; |
| } |
| } |
| |
| /** |
| * {@code Entry} is the common marker interface for a {@code KeyStore} |
| * entry. |
| */ |
| public static interface Entry { |
| } |
| |
| /** |
| * {@code LoadStoreParameter} represents a parameter that specifies how a |
| * {@code KeyStore} can be loaded and stored. |
| * |
| * @see KeyStore#load(LoadStoreParameter) |
| * @see KeyStore#store(LoadStoreParameter) |
| */ |
| public static interface LoadStoreParameter { |
| /** |
| * Returns the {@code ProtectionParameter} which is used to protect data |
| * in the {@code KeyStore}. |
| * |
| * @return the {@code ProtectionParameter} which is used to protect data |
| * in the {@code KeyStore}, maybe {@code null}. |
| */ |
| public ProtectionParameter getProtectionParameter(); |
| } |
| |
| /** |
| * {@code PasswordProtection} is a {@code ProtectionParameter} that protects |
| * a {@code KeyStore} using a password. |
| */ |
| public static class PasswordProtection implements ProtectionParameter, |
| Destroyable { |
| |
| // Store password |
| private char[] password; |
| |
| private boolean isDestroyed = false; |
| |
| /** |
| * Constructs a new instance of {@code PasswordProtection} with a |
| * password. A copy of the password is stored in the new {@code |
| * PasswordProtection} object. |
| * |
| * @param password |
| * the password, maybe {@code null}. |
| */ |
| public PasswordProtection(char[] password) { |
| if (password != null) { |
| this.password = password.clone(); |
| } |
| } |
| |
| /** |
| * Returns the password. |
| * |
| * @return the password. |
| * @throws IllegalStateException |
| * if the password has been destroyed. |
| */ |
| public synchronized char[] getPassword() { |
| if (isDestroyed) { |
| throw new IllegalStateException("Password was destroyed"); |
| } |
| return password; |
| } |
| |
| /** |
| * Destroys / invalidates the password. |
| * |
| * @throws DestroyFailedException |
| * if the password could not be invalidated. |
| */ |
| public synchronized void destroy() throws DestroyFailedException { |
| isDestroyed = true; |
| if (password != null) { |
| Arrays.fill(password, '\u0000'); |
| password = null; |
| } |
| } |
| |
| /** |
| * Indicates whether the password is invalidated. |
| * |
| * @return {@code true} if the password is invalidated, {@code false} |
| * otherwise. |
| */ |
| public synchronized boolean isDestroyed() { |
| return isDestroyed; |
| } |
| } |
| |
| /** |
| * {@code ProtectionParameter} is a marker interface for protection |
| * parameters. A protection parameter is used to protect the content of a |
| * {@code KeyStore}. |
| */ |
| public static interface ProtectionParameter { |
| } |
| |
| /** |
| * {@code PrivateKeyEntry} represents a {@code KeyStore} entry that |
| * holds a private key. |
| */ |
| public static final class PrivateKeyEntry implements Entry { |
| // Store Certificate chain |
| private Certificate[] chain; |
| |
| // Store PrivateKey |
| private PrivateKey privateKey; |
| |
| /** |
| * Constructs a new instance of {@code PrivateKeyEntry} with the given |
| * {@code PrivateKey} and the provided certificate chain. |
| * |
| * @param privateKey |
| * the private key. |
| * @param chain |
| * the ordered certificate chain with the certificate |
| * corresponding to the private key at index 0. |
| * @throws NullPointerException |
| * if {@code privateKey} or {@code chain} is {@code null}. |
| * @throws IllegalArgumentException |
| * if {@code chain.length == 0}, the algorithm of the |
| * private key does not match the algorithm of the public |
| * key of the first certificate or the certificates are not |
| * all of the same type. |
| */ |
| public PrivateKeyEntry(PrivateKey privateKey, Certificate[] chain) { |
| if (privateKey == null) { |
| throw new NullPointerException("privateKey == null"); |
| } |
| if (chain == null) { |
| throw new NullPointerException("chain == null"); |
| } |
| |
| if (chain.length == 0) { |
| throw new IllegalArgumentException("chain.length == 0"); |
| } |
| // Match algorithm of private key and algorithm of public key from |
| // the end certificate |
| String s = chain[0].getType(); |
| if (!(chain[0].getPublicKey().getAlgorithm()).equals(privateKey.getAlgorithm())) { |
| throw new IllegalArgumentException("Algorithm of private key does not match " + |
| "algorithm of public key in end certificate of entry (with index number: 0)"); |
| } |
| // Match certificate types |
| for (int i = 1; i < chain.length; i++) { |
| if (!s.equals(chain[i].getType())) { |
| throw new IllegalArgumentException("Certificates from the given chain have different types"); |
| } |
| } |
| // clone chain - this.chain = (Certificate[])chain.clone(); |
| boolean isAllX509Certificates = true; |
| // assert chain length > 0 |
| for(Certificate cert: chain){ |
| if(!(cert instanceof X509Certificate)){ |
| isAllX509Certificates = false; |
| break; |
| } |
| } |
| |
| if(isAllX509Certificates){ |
| this.chain = new X509Certificate[chain.length]; |
| } else { |
| this.chain = new Certificate[chain.length]; |
| } |
| System.arraycopy(chain, 0, this.chain, 0, chain.length); |
| this.privateKey = privateKey; |
| } |
| |
| /** |
| * Returns the private key. |
| * |
| * @return the private key. |
| */ |
| public PrivateKey getPrivateKey() { |
| return privateKey; |
| } |
| |
| /** |
| * Returns the certificate chain. |
| * |
| * @return the certificate chain. |
| */ |
| public Certificate[] getCertificateChain() { |
| return chain.clone(); |
| } |
| |
| /** |
| * Returns the certificate corresponding to the private key. |
| * |
| * @return the certificate corresponding to the private key. |
| */ |
| public Certificate getCertificate() { |
| return chain[0]; |
| } |
| |
| /** |
| * Returns a string containing a concise, human-readable description of |
| * this {@code PrivateKeyEntry}. |
| * |
| * @return a printable representation for this {@code PrivateKeyEntry}. |
| */ |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder( |
| "PrivateKeyEntry: number of elements in certificate chain is "); |
| sb.append(Integer.toString(chain.length)); |
| sb.append("\n"); |
| for (int i = 0; i < chain.length; i++) { |
| sb.append(chain[i].toString()); |
| sb.append("\n"); |
| } |
| return sb.toString(); |
| } |
| } |
| |
| /** |
| * {@code SecretKeyEntry} represents a {@code KeyStore} entry that |
| * holds a secret key. |
| */ |
| public static final class SecretKeyEntry implements Entry { |
| |
| // Store SecretKey |
| private final SecretKey secretKey; |
| |
| /** |
| * Constructs a new instance of {@code SecretKeyEntry} with the given |
| * {@code SecretKey}. |
| * |
| * @param secretKey |
| * the secret key. |
| * @throws NullPointerException |
| * if {@code secretKey} is {@code null}. |
| */ |
| public SecretKeyEntry(SecretKey secretKey) { |
| if (secretKey == null) { |
| throw new NullPointerException("secretKey == null"); |
| } |
| this.secretKey = secretKey; |
| } |
| |
| /** |
| * Returns the secret key. |
| * |
| * @return the secret key. |
| */ |
| public SecretKey getSecretKey() { |
| return secretKey; |
| } |
| |
| /** |
| * Returns a string containing a concise, human-readable description of |
| * this {@code SecretKeyEntry}. |
| * |
| * @return a printable representation for this {@code |
| * SecretKeyEntry}. |
| */ |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder("SecretKeyEntry: algorithm - "); |
| sb.append(secretKey.getAlgorithm()); |
| return sb.toString(); |
| } |
| } |
| |
| /** |
| * {@code TrustedCertificateEntry} represents a {@code KeyStore} entry that |
| * holds a trusted certificate. |
| */ |
| public static final class TrustedCertificateEntry implements Entry { |
| |
| // Store trusted Certificate |
| private final Certificate trustCertificate; |
| |
| /** |
| * Constructs a new instance of {@code TrustedCertificateEntry} with the |
| * given {@code Certificate}. |
| * |
| * @param trustCertificate |
| * the trusted certificate. |
| * @throws NullPointerException |
| * if {@code trustCertificate} is {@code null}. |
| */ |
| public TrustedCertificateEntry(Certificate trustCertificate) { |
| if (trustCertificate == null) { |
| throw new NullPointerException("trustCertificate == null"); |
| } |
| this.trustCertificate = trustCertificate; |
| } |
| |
| /** |
| * Returns the trusted certificate. |
| * |
| * @return the trusted certificate. |
| */ |
| public Certificate getTrustedCertificate() { |
| return trustCertificate; |
| } |
| |
| /** |
| * Returns a string containing a concise, human-readable description of |
| * this {@code TrustedCertificateEntry}. |
| * |
| * @return a printable representation for this {@code |
| * TrustedCertificateEntry}. |
| */ |
| @Override |
| public String toString() { |
| return "Trusted certificate entry:\n" + trustCertificate; |
| } |
| } |
| } |