/* * 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 libcore.io.IoUtils; import org.apache.harmony.security.fortress.Engine; /** * {@code KeyStore} is responsible for maintaining cryptographic keys and their * owners. *

* 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 final 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("type == null"); } try { Engine.SpiAndProvider sap = ENGINE.getInstance(type, null); return new KeyStore((KeyStoreSpi) sap.spi, sap.provider, type); } catch (NoSuchAlgorithmException e) { throw new KeyStoreException(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 * 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); } } /** * 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("type == null"); } // return KeyStore instance try { Object spi = ENGINE.getInstance(type, provider, null); return new KeyStore((KeyStoreSpi) spi, provider, type); } catch (Exception e) { // override exception throw new KeyStoreException(e); } } /** * Returns the default type for {@code KeyStore} instances. * *

The default is specified in the {@code 'keystore.type'} property in the * file named {@code java.security} properties file. 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 = 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) { throwNotInitialized(); } 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) { throwNotInitialized(); } 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) { throwNotInitialized(); } 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) { throwNotInitialized(); } return implSpi.engineGetCreationDate(alias); } /** * Associates the given alias with the key, password and certificate chain. *

* 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) { throwNotInitialized(); } // Certificate chain is required for PrivateKey if (key != null && 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. *

* If the specified alias already exists, it will be reassigned. *

* 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) { throwNotInitialized(); } implSpi.engineSetKeyEntry(alias, key, chain); } /** * Associates the given alias with a certificate. *

* 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) { throwNotInitialized(); } 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) { throwNotInitialized(); } 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 aliases() throws KeyStoreException { if (!isInit) { throwNotInitialized(); } 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) { throwNotInitialized(); } 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) { throwNotInitialized(); } 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) { throwNotInitialized(); } 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) { throwNotInitialized(); } 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) { throwNotInitialized(); } 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) { throwNotInitialized(); } //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) { throwNotInitialized(); } 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) { throwNotInitialized(); } 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}. *

* 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) { throwNotInitialized(); } 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 entryClass) throws KeyStoreException { if (alias == null) { throw new NullPointerException("alias == null"); } if (entryClass == null) { throw new NullPointerException("entryClass == null"); } if (!isInit) { throwNotInitialized(); } 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); } /** * Returns a new {@code Builder} that creates a new {@code KeyStore} * based on the provided arguments. *

* 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); } /** * Returns a new {@code Builder} that creates a new {@code KeyStore} * based on the provided arguments. *

* 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); } /* * 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; /** * Constructor BuilderImpl initializes private fields: keyStore, * protParameter, typeForKeyStore providerForKeyStore fileForLoad, * isGetKeyStore */ BuilderImpl(KeyStore ks, ProtectionParameter pp, File file, String type, Provider provider) { keyStore = ks; protParameter = pp; fileForLoad = file; typeForKeyStore = type; providerForKeyStore = provider; isGetKeyStore = false; lastException = null; } /** * 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 { // get KeyStore instance using type or type and provider final KeyStore ks = (providerForKeyStore == null ? KeyStore .getInstance(typeForKeyStore) : KeyStore .getInstance(typeForKeyStore, providerForKeyStore)); // protection parameter should be PasswordProtection // or CallbackHandlerProtection final char[] passwd; 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 if (fileForLoad != null) { FileInputStream fis = null; try { fis = new FileInputStream(fileForLoad); ks.load(fis, passwd); } finally { IoUtils.closeQuietly(fis); } } else { ks.load(new TmpLSParameter(protParameter)); } 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; } } }