903 lines · 33.2 KB · Java
RawDownload
/* * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code 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.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 in the LICENSE file that * accompanied this code). * * 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package com.sun.crypto.provider; import java.io.*;import java.util.*;import java.security.DigestInputStream;import java.security.DigestOutputStream;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;import java.security.Key;import java.security.PrivateKey;import java.security.KeyStoreSpi;import java.security.KeyStoreException;import java.security.UnrecoverableKeyException;import java.security.cert.Certificate;import java.security.cert.CertificateFactory;import java.security.cert.X509Certificate;import java.security.cert.CertificateException;import java.security.spec.InvalidKeySpecException;import javax.crypto.SealedObject; /** * This class provides the keystore implementation referred to as "jceks". * This implementation strongly protects the keystore private keys using * triple-DES, where the triple-DES encryption/decryption key is derived from * the user's password. * The encrypted private keys are stored in the keystore in a standard format, * namely the <code>EncryptedPrivateKeyInfo</code> format defined in PKCS #8. * * @author Jan Luehe * * * @see java.security.KeyStoreSpi */ public final class JceKeyStore extends KeyStoreSpi {     private static final int JCEKS_MAGIC = 0xcececece;    private static final int JKS_MAGIC = 0xfeedfeed;    private static final int VERSION_1 = 0x01;    private static final int VERSION_2 = 0x02;     // Private key and supporting certificate chain    private static final class PrivateKeyEntry {        Date date; // the creation date of this entry        byte[] protectedKey;        Certificate chain[];    };     // Secret key    private static final class SecretKeyEntry {        Date date; // the creation date of this entry        SealedObject sealedKey;    }     // Trusted certificate    private static final class TrustedCertEntry {        Date date; // the creation date of this entry        Certificate cert;    };     /**     * Private keys and certificates are stored in a hashtable.     * Hash entries are keyed by alias names.     */    private Hashtable entries = new Hashtable();     /**     * 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 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 Key engineGetKey(String alias, char[] password)        throws NoSuchAlgorithmException, UnrecoverableKeyException    {        Key key = null;         Object entry = entries.get(alias.toLowerCase());         if (!((entry instanceof PrivateKeyEntry) ||              (entry instanceof SecretKeyEntry))) {            return null;        }         KeyProtector keyProtector = new KeyProtector(password);         if (entry instanceof PrivateKeyEntry) {            byte[] encrBytes = ((PrivateKeyEntry)entry).protectedKey;            EncryptedPrivateKeyInfo encrInfo;            try {                encrInfo = new EncryptedPrivateKeyInfo(encrBytes);            } catch (IOException ioe) {                throw new UnrecoverableKeyException("Private key not stored "                                                    + "as PKCS #8 " +                                                    "EncryptedPrivateKeyInfo");            }            key = keyProtector.recover(encrInfo);        } else {            key =                keyProtector.unseal(((SecretKeyEntry)entry).sealedKey);        }         return key;    }     /**     * 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).     */    public Certificate[] engineGetCertificateChain(String alias)    {        Certificate[] chain = null;         Object entry = entries.get(alias.toLowerCase());         if ((entry instanceof PrivateKeyEntry)            && (((PrivateKeyEntry)entry).chain != null)) {            chain = (Certificate[])((PrivateKeyEntry)entry).chain.clone();        }         return chain;    }     /**     * 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.     */    public Certificate engineGetCertificate(String alias) {        Certificate cert = null;         Object entry = entries.get(alias.toLowerCase());         if (entry != null) {            if (entry instanceof TrustedCertEntry) {                cert = ((TrustedCertEntry)entry).cert;            } else if ((entry instanceof PrivateKeyEntry) &&                       (((PrivateKeyEntry)entry).chain != null)) {                cert = ((PrivateKeyEntry)entry).chain[0];            }        }         return cert;    }     /**     * 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     */    public Date engineGetCreationDate(String alias) {        Date date = null;         Object entry = entries.get(alias.toLowerCase());         if (entry != null) {            // We have to create a new instance of java.util.Date because            // dates are not immutable            if (entry instanceof TrustedCertEntry) {                date = new Date(((TrustedCertEntry)entry).date.getTime());            } else if (entry instanceof PrivateKeyEntry) {                date = new Date(((PrivateKeyEntry)entry).date.getTime());            } else {                date = new Date(((SecretKeyEntry)entry).date.getTime());            }        }         return date;    }     /**     * 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 given key cannot be protected, or     * this operation fails for some other reason     */    public void engineSetKeyEntry(String alias, Key key, char[] password,                                  Certificate[] chain)        throws KeyStoreException    {        synchronized(entries) {            try {                KeyProtector keyProtector = new KeyProtector(password);                 if (key instanceof PrivateKey) {                    PrivateKeyEntry entry = new PrivateKeyEntry();                    entry.date = new Date();                     // protect the private key                    entry.protectedKey = keyProtector.protect((PrivateKey)key);                     // clone the chain                    if ((chain != null) &&                        (chain.length !=0)) {                        entry.chain = (Certificate[])chain.clone();                    } else {                        entry.chain = null;                    }                     // store the entry                    entries.put(alias.toLowerCase(), entry);                 } else {                    SecretKeyEntry entry = new SecretKeyEntry();                    entry.date = new Date();                     // seal and store the key                    entry.sealedKey = keyProtector.seal(key);                    entries.put(alias.toLowerCase(), entry);                }             } catch (Exception e) {                throw new KeyStoreException(e.getMessage());            }        }    }     /**     * 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 this operation fails.     */    public void engineSetKeyEntry(String alias, byte[] key,                                  Certificate[] chain)        throws KeyStoreException    {        synchronized(entries) {            // We assume it's a private key, because there is no standard            // (ASN.1) encoding format for wrapped secret keys            PrivateKeyEntry entry = new PrivateKeyEntry();            entry.date = new Date();             entry.protectedKey = (byte[])key.clone();            if ((chain != null) &&                (chain.length != 0)) {                entry.chain = (Certificate[])chain.clone();            } else {                entry.chain = null;            }             entries.put(alias.toLowerCase(), entry);        }    }     /**     * 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 given alias already exists and does     * not identify a <i>trusted certificate entry</i>, or this operation     * fails for some other reason.     */    public void engineSetCertificateEntry(String alias, Certificate cert)        throws KeyStoreException    {        synchronized(entries) {             Object entry = entries.get(alias.toLowerCase());            if (entry != null) {                if (entry instanceof PrivateKeyEntry) {                    throw new KeyStoreException("Cannot overwrite own "                                                + "certificate");                } else if (entry instanceof SecretKeyEntry) {                    throw new KeyStoreException("Cannot overwrite secret key");                }            }             TrustedCertEntry trustedCertEntry = new TrustedCertEntry();            trustedCertEntry.cert = cert;            trustedCertEntry.date = new Date();            entries.put(alias.toLowerCase(), trustedCertEntry);        }    }     /**     * Deletes the entry identified by the given alias from this keystore.     *     * @param alias the alias name     *     * @exception KeyStoreException if the entry cannot be removed.     */    public void engineDeleteEntry(String alias)        throws KeyStoreException    {        synchronized(entries) {            entries.remove(alias.toLowerCase());        }    }     /**     * Lists all the alias names of this keystore.     *     * @return enumeration of the alias names     */    public Enumeration engineAliases() {        return entries.keys();    }     /**     * Checks if the given alias exists in this keystore.     *     * @param alias the alias name     *     * @return true if the alias exists, false otherwise     */    public boolean engineContainsAlias(String alias) {        return entries.containsKey(alias.toLowerCase());    }     /**     * Retrieves the number of entries in this keystore.     *     * @return the number of entries in this keystore     */    public int engineSize() {        return entries.size();    }     /**     * Returns true if the entry identified by the given alias is a     * <i>key entry</i>, and false otherwise.     *     * @return true if the entry identified by the given alias is a     * <i>key entry</i>, false otherwise.     */    public boolean engineIsKeyEntry(String alias) {        boolean isKey = false;         Object entry = entries.get(alias.toLowerCase());        if ((entry instanceof PrivateKeyEntry)            || (entry instanceof SecretKeyEntry)) {            isKey = true;        }         return isKey;    }     /**     * Returns true if the entry identified by the given alias is a     * <i>trusted certificate entry</i>, and false otherwise.     *     * @return true if the entry identified by the given alias is a     * <i>trusted certificate entry</i>, false otherwise.     */    public boolean engineIsCertificateEntry(String alias) {        boolean isCert = false;        Object entry = entries.get(alias.toLowerCase());        if (entry instanceof TrustedCertEntry) {            isCert = true;        }        return isCert;    }     /**     * 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.     */    public String engineGetCertificateAlias(Certificate cert) {        Certificate certElem;         Enumeration e = entries.keys();        while (e.hasMoreElements()) {            String alias = (String)e.nextElement();            Object entry = entries.get(alias);            if (entry instanceof TrustedCertEntry) {                certElem = ((TrustedCertEntry)entry).cert;            } else if ((entry instanceof PrivateKeyEntry) &&                       (((PrivateKeyEntry)entry).chain != null)) {                certElem = ((PrivateKeyEntry)entry).chain[0];            } else {                continue;            }            if (certElem.equals(cert)) {                return alias;            }        }        return null;    }     /**     * 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 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 void engineStore(OutputStream stream, char[] password)        throws IOException, NoSuchAlgorithmException, CertificateException    {        synchronized(entries) {

Lines 1–500 of 903.