/* * @(#)KeyStore.java 1.37 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. * */ package java.security; import java.io.*; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.util.*; /** * This class represents an in-memory collection of keys and certificates. * It manages two types of entries: * * <ul> * <li><b>Key Entry</b> * <p>This type of keystore entry holds very sensitive cryptographic key * information, which is stored in a protected format to prevent unauthorized * access. * * <p>Typically, a key stored in this type of entry is a secret key, or a * private key accompanied by the certificate chain for the corresponding * public key. * * <p>Private keys and certificate chains are used by a given entity for * self-authentication. Applications for this authentication include software * distribution organizations which sign JAR files as part of releasing * and/or licensing software.<p> * * <li><b>Trusted Certificate Entry</b> * <p>This type of entry contains a single public key certificate belonging to * another party. It is called a <i>trusted certificate</i> because the * keystore owner trusts that the public key in the certificate indeed belongs * to the identity identified by the <i>subject</i> (owner) of the * certificate. * * <p>This type of entry can be used to authenticate other parties. * </ul> * * <p>Each entry in a keystore is identified by an "alias" string. In the * case of private keys and their associated certificate chains, these strings * distinguish among the different ways in which the entity may authenticate * itself. For example, the entity may authenticate itself using different * certificate authorities, or using different public key algorithms. * * <p>Whether keystores are persistent, and the mechanisms used by the * keystore if it is persistent, are not specified here. This allows * use of a variety of techniques for protecting sensitive (e.g., private or * secret) keys. Smart cards or other integrated cryptographic engines * (SafeKeyper) are one option, and simpler mechanisms such as files may also * be used (in a variety of formats). * * <p>There are two ways to request a KeyStore object: by * specifying either just a keystore type, or both a keystore type * and a package provider. * * <ul> * <li>If just a keystore type is specified: * <pre> * KeyStore ks = KeyStore.getInstance("JKS"); * </pre> * the system will determine if there is an implementation of the keystore type * requested available in the environment, and if there is more than one, if * there is a preferred one.<p> * * <li>If both a keystore type and a package provider are specified: * <pre> * KeyStore ks = KeyStore.getInstance("JKS", "SUN"); * </pre> * the system will determine if there is an implementation of the * keystore type in the package requested, and throw an exception if there * is not. * * </ul> * * <p>Before a keystore can be accessed, it must be * {@link #load(java.io.InputStream, char[]) loaded}. In order to create * an empty keystore, you pass <code>null</code> * as the <code>InputStream</code> argument to the <code>load</code> method. * * @author Jan Luehe * * @version 1.29, 02/02/00 * * @see java.security.PrivateKey * @see java.security.cert.Certificate * * @since 1.2 */ public class KeyStore { /* * Constant to lookup in the Security properties file to determine * the default keystore type. * In the Security properties file, the default keystore type is given as: * <pre> * keystore.type=jks * </pre> */ private static final String KEYSTORE_TYPE = "keystore.type"; // The keystore type private String type; // The provider private Provider provider; // The provider implementation private KeyStoreSpi keyStoreSpi; // Has this keystore been initialized (loaded)? private boolean initialized = false; /** * Creates a KeyStore object of the given type, and encapsulates the given * provider implementation (SPI object) in it. * * @param keyStoreSpi the provider implementation. * @param provider the provider. * @param type the keystore type. */ protected KeyStore(KeyStoreSpi keyStoreSpi, Provider provider, String type) { this.keyStoreSpi = keyStoreSpi; this.provider = provider; this.type = type; } /** * Generates a keystore object of the given type. * * <p>If the default provider package provides a keystore implementation * of the given type, an instance of <code>KeyStore</code> containing that * implementation is returned. If the requested keystore type is not * available in the default package, other packages are searched. * * @param type the type of keystore. * See Appendix A in the <a href= * "../../../guide/security/CryptoSpec.html#AppA"> * Java Cryptography Architecture API Specification & Reference </a> * for information about standard keystore types. * * @return a keystore object of the specified type. * * @exception KeyStoreException if the requested keystore type is * not available in the default provider package or any of the other * provider packages that were searched. */ public static KeyStore getInstance(String type) throws KeyStoreException { try { Object[] objs = Security.getImpl(type, "KeyStore", (String)null); return new KeyStore((KeyStoreSpi)objs[0], (Provider)objs[1], type); } catch(NoSuchAlgorithmException nsae) { throw new KeyStoreException(type + " not found"); } catch(NoSuchProviderException nspe) { throw new KeyStoreException(type + " not found"); } } /** * Generates a keystore object for the specified keystore * type from the specified provider. * * @param type the type of keystore. * See Appendix A in the <a href= * "../../../guide/security/CryptoSpec.html#AppA"> * Java Cryptography Architecture API Specification & Reference </a> * for information about standard keystore types. * * @param provider the name of the provider. * * @return a keystore object of the specified type, as * supplied by the specified provider. * * @exception KeyStoreException if the requested keystore type is not * available from the provider. * * @exception NoSuchProviderException if the provider has not been * configured. * * @exception IllegalArgumentException if the provider name is null * or empty. * * @see Provider */ public static KeyStore getInstance(String type, String provider) throws KeyStoreException, NoSuchProviderException { if (provider == null || provider.length() == 0) throw new IllegalArgumentException("missing provider"); try { Object[] objs = Security.getImpl(type, "KeyStore", provider); return new KeyStore((KeyStoreSpi)objs[0], (Provider)objs[1], type); } catch(NoSuchAlgorithmException nsae) { throw new KeyStoreException(type + " not found"); } } /** * Generates a keystore object for the specified keystore * type from the specified provider. Note: the <code>provider</code> * doesn't have to be registered. * * @param type the type of keystore. * See Appendix A in the <a href= * "../../../guide/security/CryptoSpec.html#AppA"> * Java Cryptography Architecture API Specification & Reference </a> * for information about standard keystore types. * * @param provider the provider. * * @return a keystore object of the specified type, as * supplied by the specified provider. * * @exception KeyStoreException if the requested keystore type is not * available from the provider. * * @exception IllegalArgumentException if the <code>provider</code> is * null. * * @see Provider * * @since 1.4 */ public static KeyStore getInstance(String type, Provider provider) throws KeyStoreException { if (provider == null) throw new IllegalArgumentException("missing provider"); try { Object[] objs = Security.getImpl(type, "KeyStore", provider); return new KeyStore((KeyStoreSpi)objs[0], (Provider)objs[1], type); } catch(NoSuchAlgorithmException nsae) { throw new KeyStoreException(type + " not found"); } } /** * Returns the provider of this keystore. * * @return the provider of this keystore. */ public final Provider getProvider() { return this.provider; } /** * Returns the type of this keystore. * * @return the type of this keystore. */ public final String getType() { return this.type; } /** * Returns the key associated with the given alias, using the given * password to recover it. * * @param alias the alias name * @param password the password for recovering the key * * @return the requested key, or null if the given alias does not exist * or does not identify a <i>key entry</i>. * * @exception KeyStoreException if the keystore has not been initialized * (loaded). * @exception NoSuchAlgorithmException if the algorithm for recovering the * key cannot be found * @exception UnrecoverableKeyException if the key cannot be recovered * (e.g., the given password is wrong). */ public final Key getKey(String alias, char[] password) throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } return keyStoreSpi.engineGetKey(alias, password); } /** * Returns the certificate chain associated with the given alias. * * @param alias the alias name * * @return the certificate chain (ordered with the user's certificate first * and the root certificate authority last), or null if the given alias * does not exist or does not contain a certificate chain (i.e., the given * alias identifies either a <i>trusted certificate entry</i> or a * <i>key entry</i> without a certificate chain). * * @exception KeyStoreException if the keystore has not been initialized * (loaded). */ public final Certificate[] getCertificateChain(String alias) throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } return keyStoreSpi.engineGetCertificateChain(alias); } /** * Returns the certificate associated with the given alias. * * <p>If the given alias name identifies a * <i>trusted certificate entry</i>, the certificate associated with that * entry is returned. If the given alias name identifies a * <i>key entry</i>, the first element of the certificate chain of that * entry is returned, or null if that entry does not have a certificate * chain. * * @param alias the alias name * * @return the certificate, or null if the given alias does not exist or * does not contain a certificate. * * @exception KeyStoreException if the keystore has not been initialized * (loaded). */ public final Certificate getCertificate(String alias) throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } return keyStoreSpi.engineGetCertificate(alias); } /** * Returns the creation date of the entry identified by the given alias. * * @param alias the alias name * * @return the creation date of this entry, or null if the given alias does * not exist * * @exception KeyStoreException if the keystore has not been initialized * (loaded). */ public final Date getCreationDate(String alias) throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } return keyStoreSpi.engineGetCreationDate(alias); } /** * Assigns the given key to the given alias, protecting it with the given * password. * * <p>If the given key is of type <code>java.security.PrivateKey</code>, * it must be accompanied by a certificate chain certifying the * corresponding public key. * * <p>If the given alias already exists, the keystore information * associated with it is overridden by the given key (and possibly * certificate chain). * * @param alias the alias name * @param key the key to be associated with the alias * @param password the password to protect the key * @param chain the certificate chain for the corresponding public * key (only required if the given key is of type * <code>java.security.PrivateKey</code>). * * @exception KeyStoreException if the keystore has not been initialized * (loaded), the given key cannot be protected, or this operation fails * for some other reason */ public final void setKeyEntry(String alias, Key key, char[] password, Certificate[] chain) throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } if ((key instanceof PrivateKey) && (chain==null || chain.length==0)) { throw new IllegalArgumentException("Private key must be " + "accompanied by certificate " + "chain"); } keyStoreSpi.engineSetKeyEntry(alias, key, password, chain); } /** * Assigns the given key (that has already been protected) to the given * alias. * * <p>If the protected key is of type * <code>java.security.PrivateKey</code>, it must be accompanied by a * certificate chain certifying the corresponding public key. * * <p>If the given alias already exists, the keystore information * associated with it is overridden by the given key (and possibly * certificate chain). * * @param alias the alias name * @param key the key (in protected format) to be associated with the alias * @param chain the certificate chain for the corresponding public * key (only useful if the protected key is of type * <code>java.security.PrivateKey</code>). * * @exception KeyStoreException if the keystore has not been initialized * (loaded), or if this operation fails for some other reason. */ public final void setKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } keyStoreSpi.engineSetKeyEntry(alias, key, chain); } /** * Assigns the given certificate to the given alias. * * <p>If the given alias already exists in this keystore and identifies a * <i>trusted certificate entry</i>, the certificate associated with it is * overridden by the given certificate. * * @param alias the alias name * @param cert the certificate * * @exception KeyStoreException if the keystore has not been initialized, * or the given alias already exists and does not identify a * <i>trusted certificate entry</i>, or this operation fails for some * other reason. */ public final void setCertificateEntry(String alias, Certificate cert) throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } keyStoreSpi.engineSetCertificateEntry(alias, cert); } /** * Deletes the entry identified by the given alias from this keystore. * * @param alias the alias name * * @exception KeyStoreException if the keystore has not been initialized, * or if the entry cannot be removed. */ public final void deleteEntry(String alias) throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } keyStoreSpi.engineDeleteEntry(alias); } /** * Lists all the alias names of this keystore. * * @return enumeration of the alias names * * @exception KeyStoreException if the keystore has not been initialized * (loaded). */ public final Enumeration aliases() throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } return keyStoreSpi.engineAliases(); } /** * Checks if the given alias exists in this keystore. * * @param alias the alias name * * @return true if the alias exists, false otherwise * * @exception KeyStoreException if the keystore has not been initialized * (loaded). */ public final boolean containsAlias(String alias) throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } return keyStoreSpi.engineContainsAlias(alias); } /** * Retrieves the number of entries in this keystore. * * @return the number of entries in this keystore * * @exception KeyStoreException if the keystore has not been initialized * (loaded). */ public final int size() throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } return keyStoreSpi.engineSize(); } /** * Returns true if the entry identified by the given alias is a * <i>key entry</i>, and false otherwise. * * @param alias the alias for the keystore entry to be checked * * @return true if the entry identified by the given alias is a * <i>key entry</i>, false otherwise. * * @exception KeyStoreException if the keystore has not been initialized * (loaded). */ public final boolean isKeyEntry(String alias) throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } return keyStoreSpi.engineIsKeyEntry(alias); } /** * Returns true if the entry identified by the given alias is a * <i>trusted certificate entry</i>, and false otherwise. * * @param alias the alias for the keystore entry to be checked * * @return true if the entry identified by the given alias is a * <i>trusted certificate entry</i>, false otherwise. * * @exception KeyStoreException if the keystore has not been initialized * (loaded). */ public final boolean isCertificateEntry(String alias) throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } return keyStoreSpi.engineIsCertificateEntry(alias); } /** * Returns the (alias) name of the first keystore entry whose certificate * matches the given certificate. * * <p>This method attempts to match the given certificate with each * keystore entry. If the entry being considered * is a <i>trusted certificate entry</i>, the given certificate is * compared to that entry's certificate. If the entry being considered is * a <i>key entry</i>, the given certificate is compared to the first * element of that entry's certificate chain (if a chain exists). * * @param cert the certificate to match with. * * @return the (alias) name of the first entry with matching certificate, * or null if no such entry exists in this keystore. * * @exception KeyStoreException if the keystore has not been initialized * (loaded). */ public final String getCertificateAlias(Certificate cert) throws KeyStoreException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } return keyStoreSpi.engineGetCertificateAlias(cert); } /** * Stores this keystore to the given output stream, and protects its * integrity with the given password. * * @param stream the output stream to which this keystore is written. * @param password the password to generate the keystore integrity check * * @exception KeyStoreException if the keystore has not been initialized * (loaded). * @exception IOException if there was an I/O problem with data * @exception NoSuchAlgorithmException if the appropriate data integrity * algorithm could not be found * @exception CertificateException if any of the certificates included in * the keystore data could not be stored */ public final void store(OutputStream stream, char[] password) throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException { if (!initialized) { throw new KeyStoreException("Uninitialized keystore"); } keyStoreSpi.engineStore(stream, password); } /** * Loads this KeyStore from the given input stream. * * <p>If a password is given, it is used to check the integrity of the * keystore data. Otherwise, the integrity of the keystore is not checked. * * <p>In order to create an empty keystore, or if the keystore cannot * be initialized from a stream (e.g., because it is stored on a hardware * token device), you pass <code>null</code> * as the <code>stream</code> argument. * * <p> Note that if this KeyStore has already been loaded, it is * reinitialized and loaded again from the given input stream. * * @param stream the input stream from which the keystore is loaded, or * null if an empty keystore is to be created. * @param password the (optional) password used to check the integrity of * the keystore. * * @exception IOException if there is an I/O or format problem with the * keystore data * @exception NoSuchAlgorithmException if the algorithm used to check * the integrity of the keystore cannot be found * @exception CertificateException if any of the certificates in the * keystore could not be loaded */ public final void load(InputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException { keyStoreSpi.engineLoad(stream, password); initialized = true; } /** * Returns the default keystore type as specified in the Java security * properties file, or the string "jks" (acronym for "Java keystore") * if no such property exists. * The Java security properties file is located in the file named * <JAVA_HOME>/lib/security/java.security, where <JAVA_HOME> * refers to the directory where the SDK was installed. * * <p>The default keystore type can be used by applications that do not * want to use a hard-coded keystore type when calling one of the * <code>getInstance</code> methods, and want to provide a default keystore * type in case a user does not specify its own. * * <p>The default keystore type can be changed by setting the value of the * "keystore.type" security property (in the Java security properties * file) to the desired keystore type. * * @return the default keystore type as specified in the * Java security properties file, or the string "jks" * if no such property exists. */ public final static String getDefaultType() { String kstype; kstype = (String)AccessController.doPrivileged(new PrivilegedAction() { public Object run() { return Security.getProperty(KEYSTORE_TYPE); } }); if (kstype == null) { kstype = "jks"; } return kstype; } }