com.adito.boot.KeyStoreManager.java Source code

Java tutorial

Introduction

Here is the source code for com.adito.boot.KeyStoreManager.java

Source

/*
*  Adito
*
*  Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU General Public License
*  as published by the Free Software Foundation; either version 2 of
*  the License, or (at your option) any later version.
*  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 for more details.
*
*  You should have received a copy of the GNU General Public
*  License along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

package com.adito.boot;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.Principal;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.maverick.crypto.asn1.ASN1Sequence;
import com.maverick.crypto.asn1.DERInputStream;
import com.maverick.crypto.asn1.x509.X509CertificateStructure;
import com.maverick.ssl.TrustedCACertStore;

/**
 * <p>
 * Manages one or more keystores. Adito currently uses two keystores, one
 * for the SSL server certificate and one for storing all of the client
 * certificates.
 * </p>
 * 
 * <p>
 * Before a keystore manager may be used, it must be registered using
 * {@link #registerKeyStore(String, String, boolean, String, KeyStoreType)}
 * 
 * <p>
 * To obtain a keystore, use {@link #getInstance(String)}, passing the keystore
 * name. If the named keystore has not yet been initialised then it is created
 * and initialised, otherwise the last used instance is returned.
 * </p>
 * 
 * <p>
 * The key store files are held and manipulated in the <i>conf</i> directory.
 * All key stores are also updated to the
 * {@link com.adito.boot.Repository} which is loaded at start up,
 * replacing all the files.
 * </p>
 * 
 * @see com.adito.boot.Repository
 */
public class KeyStoreManager {

    // Public statics

    /**
     * The default key store name. Used to store Aditos own server
     * certificate
     */
    public static final String DEFAULT_KEY_STORE = "default";

    /**
     * Key store name for Server authentication certificates used to store
     * certificates to use to connect to other servers
     */
    public static final String SERVER_AUTHENTICATION_CERTIFICATES_KEY_STORE = "serverAuthentication";

    /**
     * Key Store name for Server certificates that are trusted by Adito
     * making outgoing connections to it.
     */
    public static final String TRUSTED_SERVER_CERTIFICATES_KEY_STORE = "trustedServer";

    /**
     * Default password used for storing the untrusted key
     */
    public static final String DEFAULT_KEY_PASSWORD = "adito";

    /**
     * Repository name
     */
    public static final String KEYSTORE_REPOSITORY = "keystore";

    // Private instance variables

    private boolean keyStoreExists;
    private Date keystoreLastModified;
    private KeyStore keyStore;
    private boolean keyStoreEmpty;
    private File keyStoreFile;
    private Throwable keyStoreException;
    private String keyStoreName;
    private KeyStoreType keyStoreType;
    private String bundle;
    private boolean removeable;
    private String storePassword;

    // Private statics
    final static Log log = LogFactory.getLog(KeyStoreManager.class);
    static String KEY_TOOL = SystemProperties.get("java.home") + File.separator + "bin" + File.separator
            + "keytool";
    private static HashMap<String, KeyStoreManager> instances = new HashMap<String, KeyStoreManager>();

    /**
     * Constant for jks keystore 
     */
    public static final KeyStoreType TYPE_JKS = new KeyStoreType("JKS", "jks");

    /**
     * Constant for pkcs12 keystore   
     */
    public static final KeyStoreType TYPE_PKCS12 = new KeyStoreType("PKCS12", "p12");

    private static final List keyStoreTypes = Arrays.asList(new KeyStoreType[] { TYPE_JKS, TYPE_PKCS12 });

    /**
     * Constructor. Private to prevent direct instantiation
     * 
     * @param keyStoreName name of key store
     * @param bundle bundle key from which to get key store messages (title,
     *        description etc)
     * @param removeable admin may remove certificates manually in the key store
     *        management page
     * @param storePassword the keystore password
     * @param type 
     */
    private KeyStoreManager(String keyStoreName, String bundle, boolean removeable, String storePassword,
            KeyStoreType type) {
        super();

        this.keyStoreName = keyStoreName;
        this.bundle = bundle;
        this.removeable = removeable;
        this.storePassword = storePassword;
        this.keyStoreType = type;

        initKeyStoreFile();

        // Make sure that this keystore is synchronized with the repository

        try {
            synchronizeWithRepository();
        } catch (IOException ex) {
            log.error("The keystore could not be synchornized with the repository", ex);
        }
    }

    /**
     * Get an instance of a keystore manager given the keystore name
     * 
     * @param keyStoreName
     * @return keyStore instance
     */
    public static KeyStoreManager getInstance(String keyStoreName) {
        KeyStoreManager mgr = (KeyStoreManager) instances.get(keyStoreName);
        if (mgr == null) {
            throw new IllegalArgumentException("No keystore named " + keyStoreName);
        }
        return mgr;
    }

    /**
     * @return InputStream
     * @throws IOException
     */
    public InputStream getInputStream() throws IOException {
        return RepositoryFactory.getRepository().getStore(KEYSTORE_REPOSITORY)
                .getEntryInputStream(keyStoreFile.getName());
    }

    /**
     * Get a list of registered {@link KeyStoreManager}s.
     * 
     * @return key stores
     */
    public static List<KeyStoreManager> getKeyStores() {
        List<KeyStoreManager> keyStoreList = new ArrayList<KeyStoreManager>();
        for (KeyStoreManager manager : instances.values()) {
            keyStoreList.add(manager);
        }
        return keyStoreList;
    }

    /**
     * Register a new keystore
     * 
     * @param name name of keystore
     * @param bundle bundle for messages
     * @param removeable <code>true</code> if certificates may manually be
     *        removed
     * @param storePassword key store password
     * @param type 
     */
    public static void registerKeyStore(String name, String bundle, boolean removeable, String storePassword,
            KeyStoreType type) {
        if (log.isInfoEnabled())
            log.info("Registering keystore " + name);
        KeyStoreManager mgr = new KeyStoreManager(name, bundle, removeable, storePassword, type);
        instances.put(name, mgr);
    }

    /**
     * Set the new store password. Note, this only sets the password to use for
     * reading the key store. It does not change the password of the key store
     * itself.
     * 
     * @param storePassword store password
     */
    public void setStorePassword(String storePassword) {
        this.storePassword = storePassword;
        reloadKeystore();
    }

    /**
     * Get if certificates are removeable by the administrator
     * 
     * @return removeable
     */
    public boolean getRemoveable() {
        return removeable;
    }

    /**
     * Get the bundle that contains messages for this key store
     * 
     * @return bundle
     */
    public String getBundle() {
        return bundle;
    }

    /**
     * Get the name that this key store was registered with
     * 
     * @return name
     */
    public String getName() {
        return keyStoreName;
    }

    /**
     * Get if the keystore currently exists
     * 
     * @return keystore exists
     */
    public boolean isKeyStoreExists() {
        try {
            checkKeyStore();
        } catch (Exception e) {
            log.error("Could not determine if key store exists.");
        }
        return keyStoreExists;
    }

    /**
     * Get if the keystore is empty.
     * 
     * @return keystore is empty
     */
    public boolean isKeyStoreEmpty() {
        try {
            checkKeyStore();
        } catch (Exception e) {
            log.error("Could not determine if key store exists.");
        }
        return keyStoreEmpty;
    }

    /**
     * Determine whether the certificate with the supplied alias is trusted or
     * not.
     * 
     * @param alias certificiate name
     * @return trust certificate
     */
    public boolean isCertificateTrusted(String alias) {
        try {
            checkKeyStore();
            if (isKeyStoreExists() && !isKeyStoreEmpty()) {
                return doIsCertificateTrused(alias, keyStore);
            }
        } catch (Exception e) {
            log.error("Could not determine if certificate " + alias + " is trusted.", e);
        }
        return false;
    }

    /**
     * If there were any errors loading or iniatilising the keystore, this
     * method will a non-null exception object detailing the error. If the
     * keystore was loaded successfully then <code>null</code> will be
     * returned.
     * 
     * @return exception caught whilst initialising the keystore
     */
    public Throwable getKeyStoreException() {
        checkKeyStore();
        return keyStoreException;
    }

    /**
     * Get the {@link KeyStore} this keystore manager is managing.
     * 
     * @return keystore
     */
    public KeyStore getKeyStore() {
        if (keyStore == null)
            this.reloadKeystore();

        return keyStore;
    }

    /**
     * Get a certificate given its alias.
     * 
     * @param alias certificate alias.
     * @return certificate
     */
    public Certificate getCertificate(String alias) {
        try {
            checkKeyStore();
            if (isKeyStoreExists() && !isKeyStoreEmpty()) {
                return keyStore.getCertificate(alias);
            }
        } catch (Exception e) {
            log.error("Could not get certificate with alias " + alias + ".", e);
        }
        return null;
    }

    /**
     * Return an enumeration of {@link String} objects aliases or
     * <code>null</code> if the key store is not loaded.
     * 
     * @return enumeration of {@link Certificate} objects.
     */
    public Enumeration getCertificateAliases() {
        checkKeyStore();
        try {
            if (keyStore != null) {
                return keyStore.aliases();
            }
        } catch (Exception e) {
            log.error("Could not get certificates.", e);
        }
        return null;
    }

    /**
     * Get the number of keys / certificates in this key store
     * 
     * @return number of keys / certificates in this key store
     */
    public int getSize() {
        checkKeyStore();
        try {
            return keyStore != null ? keyStore.size() : 0;
        } catch (KeyStoreException e) {
            log.error("Failed to determine size of key store.", e);
        }
        return 0;
    }

    /**
     * Change the password used to encrypt this key store.
     * 
     * @param oldPassword old password
     * @param password new password
     * @throws Exception on any error
     */
    public void changeKeystorePassword(String oldPassword, String password) throws Exception {
        checkKeyStore();
        if (!isKeyStoreExists()) {
            throw new Exception("Key store doesn't exists. Password cannot be changed.");
        }
        CommandRunner runner = null;
        try {
            Vector<String> v = new Vector<String>();
            v.add(KEY_TOOL);
            v.add("-storepasswd");
            v.add("-new");
            v.add(password);
            v.add("-keystore");
            v.add(getKeyStoreFile().getAbsolutePath());
            v.add("-storepass");
            v.add(oldPassword);
            runner = new CommandRunner(v);
            runner.runCommand();
            this.storePassword = password;
        } catch (Exception e) {
            log.error("Failed to change keystore password.", e);
            throw new Exception(runner == null ? e.getMessage() : parseKeytoolOutput(runner.getOutput()));
        }

    }

    /**
     * Get a key pair from this key store
     * 
     * @param alias alias under which the pair is stored
     * @param password password protecting the keys if any
     * @return key pair
     */
    public KeyPair getKeyPair(String alias, char[] password) {
        try {
            checkKeyStore();
            if (isKeyStoreExists() && !isKeyStoreEmpty()) {
                Key key = keyStore.getKey(alias, password);
                if (key instanceof PrivateKey) {
                    Certificate cert = keyStore.getCertificate(alias);
                    PublicKey publicKey = cert.getPublicKey();
                    return new KeyPair(publicKey, (PrivateKey) key);
                }
            }
        } catch (Exception e) {
            log.error("Could not get key pair with alias " + alias + ".", e);
        }
        return null;
    }

    /**
     * Get a private key from this key store
     * 
     * @param alias alias under which the key is stored
     * @param password password protecting the key if any
     * @return key
     */
    public PrivateKey getPrivateKey(String alias, char[] password) {
        try {
            checkKeyStore();
            if (isKeyStoreExists() && !isKeyStoreEmpty()) {
                return (PrivateKey) keyStore.getKey(alias, password);
            }
        } catch (Exception e) {
            log.error("Could not get private key with alias " + alias + ".", e);
        }
        return null;
    }

    /**
     * Get the chain of certificates from the specified alias up to the root CA
     * certificate
     * 
     * @param alias alias
     * @return certificate chain
     */

    public Certificate[] getCertificateChain(String alias) {
        Certificate[] chain = null;
        try {
            checkKeyStore();
            if (isKeyStoreExists() && !isKeyStoreEmpty()) {
                chain = keyStore.getCertificateChain(alias);
            }
        } catch (Exception e) {
            log.error(e);
        }
        if (chain == null) {
            log.error("Could not get private key with alias " + alias + ".");
        }
        return chain;
    }

    /**
     * Utility method to extract an entity from a certificates subject DN
     * 
     * @param c certificate
     * @param entity entity to extract
     * @return entity value
     */
    public static String getX509CertificateEntity(X509Certificate c, String entity) {
        // This assumes the keystore returns the last certificate in the chain
        // the actual certifcate that is signed by a CA or untrusted cert
        Principal subjectPrincipal = c.getSubjectDN();
        StringTokenizer t = new StringTokenizer(subjectPrincipal.getName(), ",");
        while (t.hasMoreTokens()) {
            String e = t.nextToken().trim();
            String f = entity.trim() + "=";
            if (e.toLowerCase().startsWith(f.toLowerCase())) {
                return e.substring(f.length()).trim();
            }
        }
        return "";
    }

    /**
     * Reload the key store this manager is managing
     */
    public void reloadKeystore() {
        keyStoreExists = false;
        keyStoreException = null;
        keyStoreEmpty = true;
        keyStore = null;
        try {
            File keystoreFile = getKeyStoreFile();
            InputStream in = null;
            if (keystoreFile.exists() && keystoreFile.canRead()) {
                keyStoreExists = true;
                keyStoreException = null;
                keyStoreEmpty = true;
                keyStore = null;
                try {
                    keyStore = KeyStore.getInstance(keyStoreType.getName());
                    String keystorePassword = getKeyStorePassword();
                    if (keystoreFile.length() != 0) {
                        in = new FileInputStream(keystoreFile);
                        keyStore.load(in, keystorePassword.toCharArray());
                        keyStoreEmpty = keyStore.size() == 0;
                    }
                } finally {
                    Util.closeStream(in);
                }
            } else {
                // No change
            }
        } catch (Exception e) {
            log.error("Failed to check key store.", e);
            keyStoreException = e;
        }
    }

    /**
     * Check the check store to see if it has been modified since it was last
     * loaded, loading it if it has changed
     */
    public void checkKeyStore() {
        initKeyStoreFile();
        try {
            File keystoreFile = getKeyStoreFile();
            if (keystoreFile.exists() && keystoreFile.canRead()) {
                Date fileLastModified = new Date(keystoreFile.lastModified());
                if (keystoreLastModified == null || !keystoreLastModified.equals(fileLastModified)) {
                    keystoreLastModified = fileLastModified;
                    reloadKeystore();
                } else {
                    // No change
                }
            } else {
                keyStore = null;
                keyStoreExists = false;
                keyStoreEmpty = true;
                keyStoreException = null;
            }
        } catch (Exception e) {
            log.error("Failed to check key store.", e);
            keyStoreException = e;
        }
    }

    /**
     * Import a key in PKCS12 key format
     * 
     * @param keyFile file to import
     * @param password password for key
     * @param alias alias for key
     * @param newAlias 
     * @throws Exception on any error
     * @return the alias of the key imported
     */
    public String importPKCS12Key(File keyFile, String password, String alias, String newAlias) throws Exception {
        KeyStore kspkcs12 = KeyStore.getInstance("PKCS12");
        kspkcs12.load(new FileInputStream(keyFile), password == null ? null : password.toCharArray());
        boolean hasTemp = false;
        if (isKeyStoreEmpty()) {
            if (isKeyStoreExists()) {
                deleteKeyStore();
            }
            createKeyStore();
            String dname = "cn=tmp, ou=tmp, o=tmp, l=tmp, st=tmp, c=GB";
            createKey("temporary-key", dname);
            hasTemp = true;
            reloadKeystore();
        }
        try {

            String firstAlias = (String) kspkcs12.aliases().nextElement();

            if (Util.isNullOrTrimmedBlank(alias)) {
                log.info("Alias not specified, importing first alias " + firstAlias);
                alias = firstAlias;
            }

            if (Util.isNullOrTrimmedBlank(newAlias)) {
                log.info("New alias not specified, using imported alias " + alias);
                newAlias = alias;
            }

            Certificate c[] = kspkcs12.getCertificateChain(alias);
            // Make sure we don't have a null chain
            if (c == null)
                c = new Certificate[] {};
            Key key = kspkcs12.getKey(alias, password == null ? null : password.toCharArray());
            if (key == null) {
                throw new Exception("No alias of '" + alias + "' in imported PKCS12 key file.");
            }
            this.keyStore.setKeyEntry(newAlias, key, getKeyStorePassword().toCharArray(), c);
        } finally {
            if (hasTemp || keyStore.containsAlias("temporary-key"))
                this.keyStore.deleteEntry("temporary-key");
            OutputStream out = null;
            try {
                out = new FileOutputStream(keyStoreFile.getAbsolutePath());
                getKeyStore().store(out, getKeyStorePassword().toCharArray());
            } finally {
                Util.closeStream(out);
            }
            updateRepository(false);
        }

        return newAlias;
    }

    /**
     * Get the key store file this manager is managing
     * 
     * @return file
     */
    public File getKeyStoreFile() {
        return keyStoreFile;
    }

    /**
     * Create a new private key given an alias an DN. Note that the
     * DN will be escaped as required by RFC2253
     * 
     * @param alias alias
     * @param dname DN
     * @throws Exception on any error
     */
    public void createKey(String alias, String dname) throws Exception {
        checkKeyStore();
        if (!isKeyStoreExists()) {
            throw new Exception("Key store doesn't exists. Key cannot be created.");
        }
        /*
         * Because an empty keystore file is not valid, delete the key first
         * then let genkey create a new keystore
         */
        if (isKeyStoreEmpty()) {
            if (!getKeyStoreFile().delete()) {
                throw new Exception("Could not delete key store.");
            }
        }
        CommandRunner runner = null;
        try {
            String keyStorePassword = getKeyStorePassword();
            Vector<String> v = new Vector<String>();
            v.add(KEY_TOOL);
            v.add("-genkey");
            v.add("-alias");
            v.add(alias);
            v.add("-keyalg");
            v.add("RSA");
            v.add("-keystore");
            v.add(keyStoreFile.getAbsolutePath());
            v.add("-dname");
            v.add(dname);
            v.add("-storetype");
            v.add(keyStoreType.getName());
            v.add("-storepass");
            v.add(keyStorePassword);
            v.add("-keypass");
            v.add(keyStorePassword);
            v.add("-validity");
            v.add("365");
            runner = new CommandRunner(v);
            runner.runCommand();

            updateRepository(false);
        } catch (Exception e) {
            log.error("Failed to create key.", e);
            throw new Exception(runner == null ? e.getMessage() : parseKeytoolOutput(runner.getOutput()));
        }
    }

    /**
     * Import a certificate from a file and store with the specified a alias.
     * File must be X509 and Base 64 or DER encoded.
     * 
     * @param alias alias to store cert. under
     * @param certFile file contain certificate
     * @param keyPass key password or <code>null</code> for default 
     * @throws Exception on any error
     */
    public void importCert(String alias, File certFile, String keyPass) throws Exception {
        checkKeyStore();
        if (!isKeyStoreExists()) {
            createKeyStore();
        }
        /*
         * Because an empty keystore file is not valid, delete the key first
         * then let genkey create a new keystore
         */
        if (isKeyStoreEmpty()) {
            if (!getKeyStoreFile().delete()) {
                throw new Exception("Could not delete key store.");
            }
        }
        CommandRunner runner = null;
        try {
            if (log.isInfoEnabled())
                log.info("Importing certificate for " + alias + " from " + certFile.getAbsolutePath());
            String keyPassword = getKeyStorePassword();
            Vector<String> v = new Vector<String>();
            v.add(KEY_TOOL);
            v.add("-import");
            v.add("-trustcacerts");

            v.add("-noprompt");
            v.add("-file");
            v.add(certFile.getAbsolutePath());
            v.add("-alias");
            v.add(alias);
            v.add("-keystore");
            v.add(keyStoreFile.getAbsolutePath());
            v.add("-storepass");
            v.add(keyPassword);
            v.add("-keypass");

            v.add(keyPass == null ? DEFAULT_KEY_PASSWORD : keyPass);
            v.add("-storetype");
            v.add(keyStoreType.getName().toLowerCase());
            runner = new CommandRunner(v);
            runner.runCommand();

            updateRepository(false);
        } catch (Exception e) {
            log.error("Failed to import certficate.", e);
            throw new Exception(runner == null ? e.getMessage() : parseKeytoolOutput(runner.getOutput()));
        }
        if (log.isInfoEnabled())
            log.info("Certificate for " + alias + " imported from " + certFile.getAbsolutePath());
    }

    /**
     * Generate a certificate sigining request for the key with the specfied
     * alias.
     * 
     * @param alias alias to generate CSR for
     * @param keyPass 
     * @return CSR as a string
     * @throws Exception on any error
     */
    public String generateCSR(String alias, String keyPass) throws Exception {
        checkKeyStore();
        if (!isKeyStoreExists()) {
            throw new Exception("Key store doesn't exists. CSR cannot be generated.");
        }
        CommandRunner runner = null;
        InputStream in = null;
        try {
            String keyPassword = getKeyStorePassword();
            Vector<String> v = new Vector<String>();
            v.add(KEY_TOOL);
            v.add("-certreq");
            v.add("-alias");
            v.add(alias);
            v.add("-keyalg");
            v.add("RSA");
            v.add("-keystore");
            v.add(keyStoreFile.getAbsolutePath());
            v.add("-storepass");
            v.add(keyPassword);
            v.add("-file");
            File csrFile = new File(ContextHolder.getContext().getConfDirectory(), "server-certificate.csr");
            v.add(csrFile.getAbsolutePath());
            v.add("-keypass");
            v.add(keyPass == null ? DEFAULT_KEY_PASSWORD : keyPass);
            runner = new CommandRunner(v);
            runner.runCommand();
            in = new FileInputStream(csrFile);
            return Util.loadStreamToString(in, null);
        } catch (Exception e) {
            log.error("Failed to create key.", e);
            throw new Exception(runner == null ? e.getMessage() : parseKeytoolOutput(runner.getOutput()));
        } finally {
            Util.closeStream(in);
        }
    }

    /**
     * Create a new key store.
     * <p>
     * We dont actually create a keystore, we just create a zero length file as
     * there doesnt seem to be a way of creating an empty keystore using
     * keytool.
     * 
     * @throws IOException on any error
     */
    public void createKeyStore() throws IOException {
        if (isKeyStoreExists()) {
            throw new IOException("Key store already exists.");
        }
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(getKeyStoreFile());
        } finally {
            Util.closeStream(out);
        }
    }

    /**
     * Delete the key store.
     * 
     * @throws IOException
     */
    public void deleteKeyStore() throws IOException {
        if (!isKeyStoreExists()) {
            throw new IOException("Key store does not exist.");
        }
        if (!getKeyStoreFile().delete()) {
            throw new IOException("Failed to delete " + getKeyStoreFile().getAbsolutePath() + ".");
        }

        updateRepository(true);
    }

    /**
     * Delete a certificate from the key store given its alias.
     * 
     * @param alias alias to remove
     * @throws Exception on any error
     */
    public void deleteCertificate(String alias) throws Exception {
        checkKeyStore();
        if (!isKeyStoreExists()) {
            throw new Exception("Key store doesn't exists. Certificate cannot be deleted.");
        }
        CommandRunner runner = null;
        try {
            if (log.isInfoEnabled())
                log.info("Deleting certificate for " + alias);
            String keyPassword = getKeyStorePassword();
            Vector<String> v = new Vector<String>();
            v.add(KEY_TOOL);
            v.add("-delete");
            v.add("-alias");
            v.add(alias);
            v.add("-keystore");
            v.add(keyStoreFile.getAbsolutePath());
            v.add("-storepass");
            v.add(keyPassword);
            runner = new CommandRunner(v);
            runner.runCommand();

            updateRepository(false);
        } catch (Exception e) {
            log.error("Failed to delete certificate.", e);
            throw new Exception(runner == null ? e.getMessage() : parseKeytoolOutput(runner.getOutput()));
        }
        if (log.isInfoEnabled())
            log.info("Deleted certificate for " + alias);

    }

    /**
     * Get a {@link KeyStoreType} given its name.
     * 
     * @param name key store type name
     * @return key store type
     */
    public static KeyStoreType getKeyStoreType(String name) {
        for (Iterator i = keyStoreTypes.iterator(); i.hasNext();) {
            KeyStoreType t = (KeyStoreType) i.next();
            if (t.getName().equals(name)) {
                return t;
            }
        }
        return null;
    }

    /**
     * Get a list of supported {@link KeyStoreType} objects.
     * 
     * @return list of support key store types
     */
    public List getSupportedKeyStoreTypes() {
        return keyStoreTypes;
    }

    /**
     * Set the key store type for this key store manager.
     * 
     * @param keyStoreType key store type
     */
    public void setKeyStoreType(KeyStoreType keyStoreType) {
        this.keyStoreType = keyStoreType;
        initKeyStoreFile();
    }

    /**
     * Get the key store type for this key store manager.
     * 
     * @return key store type
     */
    public KeyStoreType getKeyStoreType() {
        return keyStoreType;
    }

    // Supporting methods

    void initKeyStoreFile() {
        this.keyStoreFile = new File(ContextHolder.getContext().getConfDirectory(),
                keyStoreName + ".keystore." + keyStoreType.getExtension());
    }

    void synchronizeWithRepository() throws IOException {

        RepositoryStore store = RepositoryFactory.getRepository().getStore(KEYSTORE_REPOSITORY);

        if (!store.hasEntry(keyStoreFile.getName())) {
            keyStoreFile.createNewFile();
        } else {
            InputStream in = null;
            OutputStream out = null;
            try {
                in = store.getEntryInputStream(keyStoreFile.getName());
                out = new FileOutputStream(keyStoreFile);
                Util.copy(in, out);
            } finally {
                Util.closeStream(in);
                Util.closeStream(out);
            }
        }
    }

    void updateRepository(boolean remove) throws IOException {

        RepositoryStore store = RepositoryFactory.getRepository().getStore(KEYSTORE_REPOSITORY);

        if (remove) {
            store.removeEntry(keyStoreFile.getName());
        } else {
            OutputStream out = null;
            InputStream in = null;
            try {
                out = store.getEntryOutputStream(keyStoreFile.getName());
                in = new FileInputStream(keyStoreFile);

                Util.copy(in, out);
            } finally {
                Util.closeStream(in);
                Util.closeStream(out);
            }
        }

    }

    /**
     * Get the key store passwords
     * 
     * @return keystore password
     * @throws Exception
     */
    public String getKeyStorePassword() throws Exception {
        return storePassword;
    }

    boolean doIsCertificateTrused(String alias, KeyStore keyStore) throws Exception {

        Certificate[] certs = keyStore.getCertificateChain(alias);

        //        try {
        //           ((CustomSSLSocketFactory)CustomSSLSocketFactory.getDefault()).checkServerTrusted((X509Certificate[])certs, "");
        //           return true;
        //        } catch(CertificateException ex) {
        if (certs == null) {
            if (log.isInfoEnabled())
                log.info("No certs for " + alias + ", untrusted.");
        } else if (certs.length > 1) {
            X509Certificate x509cert = (X509Certificate) certs[certs.length - 1];
            TrustedCACertStore store = new TrustedCACertStore();
            ByteArrayInputStream bin = new ByteArrayInputStream(x509cert.getEncoded());
            DERInputStream der = null;
            try {
                der = new DERInputStream(bin);

                ASN1Sequence certificate = (ASN1Sequence) der.readObject();
                com.maverick.crypto.asn1.x509.X509Certificate x509 = new com.maverick.crypto.asn1.x509.X509Certificate(
                        X509CertificateStructure.getInstance(certificate));
                return store.isTrustedCertificate(x509, false, false);
            } finally {
                Util.closeStream(der);
            }
        }
        //        }
        return false;

    }

    String parseKeytoolOutput(String output) {
        if (output.startsWith("keytool error: ")) {
            int idx = output.indexOf(':', 14);
            if (idx != -1) {
                output = output.substring(idx + 1);
            }
        }
        return output;
    }

    /**
     * Deregister a keystore
     * 
     * @param name name of keystore
     */
    public static void deregisterKeyStore(String name) {
        if (log.isInfoEnabled())
            log.info("Deregistering keystore " + name);
        instances.remove(name);
    }

}