Package org.apache.geronimo.security.keystore

Source Code of org.apache.geronimo.security.keystore.FileKeystoreInstance

/**
*  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 org.apache.geronimo.security.keystore;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigInteger;
import java.net.URI;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.geronimo.gbean.GBeanInfo;
import org.apache.geronimo.gbean.GBeanInfoBuilder;
import org.apache.geronimo.gbean.GBeanLifecycle;
import org.apache.geronimo.gbean.AbstractName;
import org.apache.geronimo.kernel.Kernel;
import org.apache.geronimo.management.geronimo.KeyNotFoundException;
import org.apache.geronimo.management.geronimo.KeystoreException;
import org.apache.geronimo.management.geronimo.KeystoreInstance;
import org.apache.geronimo.management.geronimo.KeystoreIsLocked;
import org.apache.geronimo.system.serverinfo.ServerInfo;
import org.apache.geronimo.crypto.asn1.ASN1InputStream;
import org.apache.geronimo.crypto.asn1.ASN1Sequence;
import org.apache.geronimo.crypto.asn1.ASN1Set;
import org.apache.geronimo.crypto.asn1.DEROutputStream;
import org.apache.geronimo.crypto.asn1.x509.X509CertificateStructure;
import org.apache.geronimo.crypto.asn1.x509.X509Name;
import org.apache.geronimo.crypto.encoders.Base64;
import org.apache.geronimo.crypto.jce.PKCS10CertificationRequest;
import org.apache.geronimo.crypto.jce.X509Principal;
import org.apache.geronimo.crypto.jce.X509V1CertificateGenerator;
import org.apache.geronimo.security.SecurityNames;

/**
* Implementation of KeystoreInstance that accesses a keystore file on the
* local filesystem, identified by the file's name (the last component of
* the name only, not the full path).
*
* @version $Rev: 698367 $ $Date: 2008-09-24 05:51:48 +0800 (Wed, 24 Sep 2008) $
*/
public class FileKeystoreInstance implements KeystoreInstance, GBeanLifecycle {
    private static final Logger log = LoggerFactory.getLogger(FileKeystoreInstance.class);
    final static String JKS = "JKS";
    private URI keystorePath; // relative path
    private ServerInfo serverInfo; // used to decode relative path
    private File keystoreFile; // Only valid after startup
    private String keystoreName;
    private String keystoreType;
    private char[] keystorePassword; // Used to "unlock" the keystore for other services
    private Map<String, char[]> keyPasswords = new HashMap<String, char[]>();
    private Kernel kernel;
    private AbstractName abstractName;
    private char[] openPassword; // The password last used to open the keystore for editing
    // The following variables are the state of the keystore, which should be chucked if the file on disk changes
    private List privateKeys = new ArrayList();
    private List trustCerts = new ArrayList();
    private KeyStore keystore;
    private long keystoreReadDate = Long.MIN_VALUE;

    public FileKeystoreInstance(ServerInfo serverInfo, URI keystorePath, String keystoreName, String keystorePassword, String keystoreType, String keyPasswords, Kernel kernel, AbstractName abstractName) {
        this.serverInfo = serverInfo;
        this.keystorePath = keystorePath;
        this.keystoreName = keystoreName;
        this.keystoreType = keystoreType;
        this.kernel = kernel;
        this.abstractName = abstractName;
        this.keystorePassword = keystorePassword == null ? null : keystorePassword.toCharArray();
        if(keyPasswords != null) {
            String[] keys = keyPasswords.split("\\]\\!\\[");
            for (int i = 0; i < keys.length; i++) {
                String key = keys[i];
                int pos = key.indexOf('=');
                this.keyPasswords.put(key.substring(0, pos), key.substring(pos+1).toCharArray());
            }
        }
    }

    public void doStart() throws Exception {
        keystoreFile = new File(serverInfo.resolveServer(keystorePath));
        if(!keystoreFile.exists() || !keystoreFile.canRead()) {
            throw new IllegalArgumentException("Invalid keystore file ("+keystorePath+" = "+keystoreFile.getAbsolutePath()+")");
        }
    }

    public void doStop() throws Exception {
    }

    public void doFail() {
    }

    public static final GBeanInfo GBEAN_INFO;

    static {
        GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(FileKeystoreInstance.class, SecurityNames.KEYSTORE_INSTANCE);
        infoFactory.addAttribute("keystorePath", URI.class, true, false);
        infoFactory.addAttribute("keystoreName", String.class, true, false);
        infoFactory.addAttribute("keystorePassword", String.class, true, true);
        infoFactory.addAttribute("keystoreType", String.class, true, false);
        infoFactory.addAttribute("keyPasswords", String.class, true, true);
        infoFactory.addAttribute("kernel", Kernel.class, false);
        infoFactory.addAttribute("abstractName", AbstractName.class, false);
        infoFactory.addReference("ServerInfo", ServerInfo.class);
        infoFactory.addInterface(KeystoreInstance.class);
        infoFactory.setConstructor(new String[]{"ServerInfo","keystorePath", "keystoreName", "keystorePassword", "keystoreType", "keyPasswords", "kernel", "abstractName"});

        GBEAN_INFO = infoFactory.getBeanInfo();
    }

    public static GBeanInfo getGBeanInfo() {
        return GBEAN_INFO;
    }


    // KeystoreInstnace interface
   
    public String getKeystoreName() {
        return keystoreName;
    }

    public String getKeystoreType() {
        return keystoreType;
    }

    public void unlockKeystore(char[] password) throws KeystoreException {
        if (password == null) {
            throw new NullPointerException("password is null");
        }
        ensureLoaded(password);
        try {
            kernel.setAttribute(abstractName, "keystorePassword", new String(password));
        } catch (Exception e) {
            throw new KeystoreException("Unable to set attribute keystorePassword on myself!", e);
        }
    }

    public void setKeystorePassword(String password) {
        keystorePassword = password == null ? null : password.toCharArray();
    }

    public void lockKeystore(char[] password) throws KeystoreException {
        try {
            kernel.setAttribute(abstractName, "keystorePassword", null);
            keyPasswords.clear();
            storePasswords();
        } catch (Exception e) {
            throw new KeystoreException("Unable to set attribute keystorePassword on myself!", e);
        }
    }

    public boolean isKeystoreLocked() {
        return keystorePassword == null;
    }

    public String[] listPrivateKeys(char[] storePassword) throws KeystoreException {
        ensureLoaded(storePassword);
        return (String[]) privateKeys.toArray(new String[privateKeys.size()]);
    }

    public void unlockPrivateKey(String alias, char[] storePassword, char[] password) throws KeystoreException {
        if (storePassword == null && keystorePassword == null) {
            throw new KeystoreException("storePassword is null and keystore is locked for availability.");
        }
        if(storePassword != null)
            getPrivateKey(alias, storePassword, password);
        else
            getPrivateKey(alias, keystorePassword, password);
        keyPasswords.put(alias, password);
        storePasswords();
    }

    public String[] getUnlockedKeys(char[] storePassword) throws KeystoreException {
        ensureLoaded(storePassword);
        return (String[]) keyPasswords.keySet().toArray(new String[keyPasswords.size()]);
    }

    public boolean isTrustStore(char[] storePassword) throws KeystoreException {
        ensureLoaded(storePassword);
        return trustCerts.size() > 0;
    }

    public void lockPrivateKey(String alias, char[] storePassword) throws KeystoreException {
        if (storePassword == null) {
            throw new NullPointerException("storePassword is null");
        }
        ensureLoaded(storePassword);
        keyPasswords.remove(alias);
        storePasswords();
    }

    private void storePasswords() throws KeystoreException {
        StringBuffer buf = new StringBuffer();
        for (Iterator it = keyPasswords.entrySet().iterator(); it.hasNext();) {
            if(buf.length() > 0) {
                buf.append("]![");
            }
            Map.Entry entry = (Map.Entry) it.next();
            buf.append(entry.getKey()).append("=").append((char[])entry.getValue());
        }
        try {
            kernel.setAttribute(abstractName, "keyPasswords", buf.length() == 0 ? null : buf.toString());
        } catch (Exception e) {
            throw new KeystoreException("Unable to save key passwords in keystore '"+keystoreName+"'", e);
        }
    }

    public void setKeyPasswords(String passwords) {} // Just so the kernel sees the new value

    /**
     * Checks whether the specified private key is locked, which is to say,
     * available for other components to use to generate socket factories.
     * Does not check whether the unlock password is actually correct.
     */
    public boolean isKeyLocked(String alias) {
        return keyPasswords.get(alias) == null;
    }

    public String[] listTrustCertificates(char[] storePassword) throws KeystoreException {
        ensureLoaded(storePassword);
        return (String[]) trustCerts.toArray(new String[trustCerts.size()]);
    }

    public void importTrustCertificate(Certificate cert, String alias, char[] storePassword) throws KeystoreException {
        if (storePassword == null) {
            throw new NullPointerException("storePassword is null");
        }
        ensureLoaded(storePassword);
        try {
            keystore.setCertificateEntry(alias, cert);
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to set certificate entry in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        }
        trustCerts.add(alias);
        saveKeystore(storePassword);
    }

    public void generateKeyPair(String alias, char[] storePassword, char[] keyPassword, String keyAlgorithm, int keySize, String signatureAlgorithm, int validity, String commonName, String orgUnit, String organization, String locality, String state, String country) throws KeystoreException {
        if (storePassword == null) {
            throw new NullPointerException("storePassword is null");
        }
        ensureLoaded(storePassword);
        try {
            KeyPairGenerator kpgen = KeyPairGenerator.getInstance(keyAlgorithm);
            kpgen.initialize(keySize);
            KeyPair keyPair = kpgen.generateKeyPair();
            X509Certificate cert = generateCertificate(keyPair.getPublic(), keyPair.getPrivate(), signatureAlgorithm,
                    validity, commonName, orgUnit, organization, locality, state, country);
   
            keystore.setKeyEntry(alias, keyPair.getPrivate(), keyPassword, new Certificate[] { cert });
            privateKeys.add(alias);
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to generate key pair in keystore '" + keystoreName + "'", e);
        } catch (InvalidKeyException e) {
            throw new KeystoreException("Unable to generate key pair in keystore '" + keystoreName + "'", e);
        } catch (SignatureException e) {
            throw new KeystoreException("Unable to generate key pair in keystore '" + keystoreName + "'", e);
        } catch (NoSuchAlgorithmException e) {
            throw new KeystoreException("Unable to generate key pair in keystore '" + keystoreName + "'", e);
        }
        saveKeystore(storePassword);
    }


    public String generateCSR(String alias, char[] storePassword) throws KeystoreException {
        ensureLoaded(storePassword);
        try {
            // find certificate by alias
            X509Certificate cert = (X509Certificate) keystore.getCertificate(alias);
            // find private key by alias
            PrivateKey key = (PrivateKey) keystore.getKey(alias, (char[])keyPasswords.get(alias));
            // generate csr
            String csr = generateCSR(cert, key);
            return csr;
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        } catch (NoSuchAlgorithmException e) {
            throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        } catch (UnrecoverableKeyException e) {
            throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        } catch (InvalidKeyException e) {
            throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        } catch (NoSuchProviderException e) {
            throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        } catch (SignatureException e) {
            throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        } catch (IOException e) {
            throw new KeystoreException("Unable to generate CSR in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        }
    }

    private String generateCSR(X509Certificate cert, PrivateKey signingKey) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchProviderException, SignatureException, KeyStoreException, IOException {
        String sigalg = cert.getSigAlgName();
        X509Name subject;
        try{
            ASN1InputStream ais = new ASN1InputStream(cert.getEncoded());
            X509CertificateStructure x509Struct = new X509CertificateStructure((ASN1Sequence)ais.readObject());
            ais.close();
            subject = x509Struct.getSubject();
        } catch(CertificateEncodingException e) {
            log.warn(e.toString()+" while retrieving subject from certificate to create CSR.  Using subjectDN instead.");
            subject = new X509Name(cert.getSubjectDN().toString());
        }
        PublicKey publicKey = cert.getPublicKey();
        ASN1Set attributes = null;

        PKCS10CertificationRequest csr = new PKCS10CertificationRequest(sigalg,
                subject, publicKey, attributes, signingKey);

        if (!csr.verify()) {
            throw new KeyStoreException("CSR verification failed");
        }

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        DEROutputStream deros = new DEROutputStream(os);
        deros.writeObject(csr.getDERObject());
        String b64 = new String(Base64.encode(os.toByteArray()));

        final String BEGIN_CERT_REQ = "-----BEGIN CERTIFICATE REQUEST-----";
        final String END_CERT_REQ = "-----END CERTIFICATE REQUEST-----";
        final int CERT_REQ_LINE_LENGTH = 70;

        StringBuffer sbuf = new StringBuffer(BEGIN_CERT_REQ).append('\n');

        int idx = 0;
        while (idx < b64.length()) {

            int len = (idx + CERT_REQ_LINE_LENGTH > b64.length()) ? b64
                    .length()
                    - idx : CERT_REQ_LINE_LENGTH;

            String chunk = b64.substring(idx, idx + len);

            sbuf.append(chunk).append('\n');
            idx += len;
        }

        sbuf.append(END_CERT_REQ);
        return sbuf.toString();
    }

    public void importPKCS7Certificate(String alias, String certbuf, char[] storePassword) throws KeystoreException {
        if (storePassword == null) {
            throw new NullPointerException("storePassword is null");
        }
        ensureLoaded(storePassword);
        InputStream is = null;
        try {
            is = new ByteArrayInputStream(certbuf.getBytes());
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            Collection certcoll = cf.generateCertificates(is);
            Certificate[] chain = new Certificate[certcoll.size()];
            Iterator iter = certcoll.iterator();
            for (int i = 0; iter.hasNext(); i++) {
                chain[i] = (Certificate) iter.next();
            }
            if(keystore.getCertificate(alias).getPublicKey().equals(chain[0].getPublicKey())) {
                char[] keyPassword = (char[])keyPasswords.get(alias);
                keystore.setKeyEntry(alias, keystore.getKey(alias, keyPassword), keyPassword, chain);
                saveKeystore(keystorePassword);
            } else {
                log.error("Error in importPKCS7Certificate.  PublicKey in the certificate received is not related to the PrivateKey in the keystore. keystore = "+keystoreName+", alias = "+alias);
            }
        } catch (CertificateException e) {
            throw new KeystoreException("Unable to import PKCS7 certificat in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to import PKCS7 certificat in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        } catch (NoSuchAlgorithmException e) {
            throw new KeystoreException("Unable to import PKCS7 certificat in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        } catch (UnrecoverableKeyException e) {
            throw new KeystoreException("Unable to import PKCS7 certificat in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Exception e) {
                }
            }
        }
    }

    public void deleteEntry(String alias, char[] storePassword) throws KeystoreException {
        if (storePassword == null) {
            throw new NullPointerException("storePassword is null");
        }
        ensureLoaded(storePassword);
        try {
            keystore.deleteEntry(alias);
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to delete key in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        }
        privateKeys.remove(alias);
        trustCerts.remove(alias);
        if (keyPasswords.containsKey(alias)) {
            keyPasswords.remove(alias);
            storePasswords();
        }
        saveKeystore(storePassword);
    }

    public KeyManager[] getKeyManager(String algorithm, String alias, char[] storePassword) throws KeystoreException {
        ensureLoaded(storePassword);
        try {
            KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(algorithm);
            if(privateKeys.size() == 1) {
                keyFactory.init(keystore, (char[]) keyPasswords.get(alias));
            } else {
                // When there is more than one private key in the keystore, we create a temporary "sub keystore"
                // with only one entry of our interest and use it
                KeyStore subKeystore = KeyStore.getInstance(keystore.getType(), keystore.getProvider());
                try {
                    subKeystore.load(null, null);
                } catch (NoSuchAlgorithmException e) {
                    // should not occur
                } catch (CertificateException e) {
                    // should not occur
                } catch (IOException e) {
                    // should not occur
                }
                subKeystore.setKeyEntry(alias, keystore.getKey(alias, (char[]) keyPasswords.get(alias)),
                                        (char[]) keyPasswords.get(alias), keystore.getCertificateChain(alias));
                keyFactory.init(subKeystore, (char[]) keyPasswords.get(alias));
            }
            return keyFactory.getKeyManagers();
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to retrieve key manager in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        } catch (NoSuchAlgorithmException e) {
            throw new KeystoreException("Unable to retrieve key manager in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        } catch (UnrecoverableKeyException e) {
            throw new KeystoreException("Unable to retrieve key manager in keystore '" + keystoreName + "' for alias '" + alias + "'", e);
        }
    }

    public TrustManager[] getTrustManager(String algorithm, char[] storePassword) throws KeystoreException {
        ensureLoaded(storePassword);
        try {
            TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(algorithm);
            trustFactory.init(keystore);
            return trustFactory.getTrustManagers();
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to retrieve trust manager in keystore '" + keystoreName + "'", e);
        } catch (NoSuchAlgorithmException e) {
            throw new KeystoreException("Unable to retrieve trust manager in keystore '" + keystoreName + "'", e);
        }
    }

    /**
     * Gets the private key with the specified alias.
     * @param alias The alias of the private key to be retrieved
     * @param storePassword The password used to access the keystore
     * @param keyPassword The password to use to protect the new key
     * @return PrivateKey with the alias specified
     */
    public PrivateKey getPrivateKey(String alias, char[] storePassword, char[] keyPasswordthrows KeyNotFoundException, KeystoreException, KeystoreIsLocked {
        ensureLoaded(storePassword);
        try {
            PrivateKey key = (PrivateKey) keystore.getKey(alias, keyPassword);
            if (key == null) {
                throw new KeyNotFoundException("Keystore '"+keystoreName+"' does not contain a private key with alias'"+alias+"'.");
            }
            return key;
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to retrieve private key from keystore", e);
        } catch (NoSuchAlgorithmException e) {
            throw new KeystoreException("Unable to retrieve private key from keystore", e);
        } catch (UnrecoverableKeyException e) {
            throw new KeystoreException("Unable to retrieve private key from keystore", e);
        }
    }

    /**
     * Gets a particular certificate from the keystore.  This may be a trust
     * certificate or the certificate corresponding to a particular private
     * key.
     * This only works if the keystore is unlocked.
     * @param alias The certificate to look at
     * @throws KeyNotFoundException
     * @throws KeyStoreException
     */
    public Certificate getCertificate(String alias, char[] storePassword) throws KeystoreIsLocked, KeyNotFoundException, KeystoreException {
        ensureLoaded(storePassword);
        try {
            Certificate cert = keystore.getCertificate(alias);
            if (cert == null) {
                throw new KeyNotFoundException("Keystore '"+keystoreName+"' does not contain a certificate with alias'"+alias+"'.");
            }
            return cert;
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to retrieve certificate from keystore", e);
        }
    }

    public String getCertificateAlias(Certificate cert, char[] storePassword) throws KeystoreException {
        ensureLoaded(storePassword);
        try {
            String alias = keystore.getCertificateAlias(cert);
            if (alias == null) {
                throw new KeyNotFoundException("Keystore '"+keystoreName+"' does not contain an alias corresponding to the given certificate.");
            }
            return alias;
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to read certificate alias from keystore", e);
        }
    }

    public Certificate[] getCertificateChain(String alias, char[] storePassword) throws KeystoreException {
        ensureLoaded(storePassword);
        try {
            Certificate[] certs = keystore.getCertificateChain(alias);
            if (certs == null) {
                throw new KeyNotFoundException("Keystore '"+keystoreName+"' does not contain a certificate chain with alias'"+alias+"'.");
            }
            return certs;
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to read certificate chain from keystore", e);
        }
    }
   
    /**
     * Gets a particular certificate from the keystore.  This may be a trust
     * certificate or the certificate corresponding to a particular private
     * key.
     * This only works if the keystore is unlocked.
     * @param alias The certificate to look at
     */
    public Certificate getCertificate(String alias) {
        if(isKeystoreLocked()) {
            return null;
        }
        try {
            return keystore.getCertificate(alias);
        } catch (KeyStoreException e) {
            log.error("Unable to read certificate from keystore", e);
        }
        return null;
    }
   
    /**
     * Changes the keystore password.
     * @param storePassword Current password for the keystore
     * @param newPassword New password for the keystore
     * @throws KeystoreException
     */
    public void changeKeystorePassword(char[] storePassword, char[] newPassword) throws KeystoreException {
        ensureLoaded(storePassword);
        saveKeystore(newPassword);
        log.info("Password changed for keystore "+keystoreName);
        openPassword = newPassword;
        if(!isKeystoreLocked()) {
            unlockKeystore(newPassword);
        }
    }
   
    /**
     * Changes the password for a private key entry in the keystore.
     * @param storePassword Password for the keystore
     * @param keyPassword Current password for the private key
     * @param newKeyPassword New password for the private key
     * @throws KeystoreException
     */
    public void changeKeyPassword(String alias, char[] storePassword, char[] keyPassword, char[] newKeyPassword) throws KeystoreException {
        ensureLoaded(storePassword);
        if(!privateKeys.contains(alias)) {
            throw new KeystoreException("No private key entry "+alias+" exists in the keystore "+keystoreName);
        }
        if(keyPasswords.containsKey(alias)) {
            if(!Arrays.equals(keyPasswords.get(alias), keyPassword)) {
                throw new KeystoreException("Incorrect password provided for private key entry "+alias);
            }
            keyPasswords.put(alias, newKeyPassword);
        }
        PrivateKey key = getPrivateKey(alias, storePassword, keyPassword);
        Certificate[] chain = getCertificateChain(alias, storePassword);
        try {
            keystore.setKeyEntry(alias, key, newKeyPassword, chain);
            saveKeystore(storePassword);
            log.info("Password changed for private key entry "+alias+" in keystore "+keystoreName+".");
            if(keyPasswords.containsKey(alias)) {
                storePasswords();
            }
        } catch(KeyStoreException e) {
            throw new KeystoreException("Could not change password for private key entry "+alias, e);
        }
    }

    // ==================== Internals =====================

    private void loadKeystoreData(char[] password) throws KeystoreException {
        InputStream in = null;
        try {
            // Make sure the keystore is loadable using the provided password before resetting the instance variables.
            KeyStore tempKeystore = KeyStore.getInstance(keystoreType);
            in = new BufferedInputStream(new FileInputStream(keystoreFile));
            long readDate = System.currentTimeMillis();
            tempKeystore.load(in, password);
            // Keystore could be loaded successfully.  Initialize the instance variables to reflect the new keystore.
            keystore = tempKeystore;
            keystoreReadDate = readDate;
            privateKeys.clear();
            trustCerts.clear();
            openPassword = password;
            Enumeration aliases = keystore.aliases();
            while (aliases.hasMoreElements()) {
                String alias = (String) aliases.nextElement();
                if(keystore.isKeyEntry(alias)) {
                    privateKeys.add(alias);
                } else if(keystore.isCertificateEntry(alias)) {
                    trustCerts.add(alias);
                }
            }
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to open keystore with provided password", e);
        } catch (IOException e) {
            throw new KeystoreException("Unable to open keystore with provided password", e);
        } catch (NoSuchAlgorithmException e) {
            throw new KeystoreException("Unable to open keystore with provided password", e);
        } catch (CertificateException e) {
            throw new KeystoreException("Unable to open keystore with provided password", e);
        } finally {
            if(in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    log.error("Error while closing keystore file "+keystoreFile.getAbsolutePath(), e);
                }
            }
        }
    }

    private boolean isLoaded(char[] password) {
        if(openPassword == null || openPassword.length != password.length) {
            return false;
        }
        if(keystoreReadDate < keystoreFile.lastModified()) {
            return false;
        }
        for (int i = 0; i < password.length; i++) {
            if(password[i] != openPassword[i]) {
                return false;
            }
        }
        return true;
    }

    private void ensureLoaded(char[] storePassword) throws KeystoreException {
        char[] password;
        if (storePassword == null) {
            if (isKeystoreLocked()) {
                throw new KeystoreIsLocked("Keystore '"+keystoreName+"' is locked; please unlock it in the console.");
            }
            password = keystorePassword;
        } else {
            password = storePassword;
        }
        if (!isLoaded(password)) {
            loadKeystoreData(password);
        }
    }
   
    private X509Certificate generateCertificate(PublicKey publicKey, PrivateKey privateKey, String algorithm, int validity, String commonName, String orgUnit, String organization, String locality, String state, String country) throws SignatureException, InvalidKeyException {
        X509V1CertificateGenerator certgen = new X509V1CertificateGenerator();
        Vector order = new Vector();
        Hashtable attrmap = new Hashtable();

        if (commonName != null) {
            attrmap.put(X509Principal.CN, commonName);
            order.add(X509Principal.CN);
        }

        if (orgUnit != null) {
            attrmap.put(X509Principal.OU, orgUnit);
            order.add(X509Principal.OU);
        }

        if (organization != null) {
            attrmap.put(X509Principal.O, organization);
            order.add(X509Principal.O);
        }

        if (locality != null) {
            attrmap.put(X509Principal.L, locality);
            order.add(X509Principal.L);
        }

        if (state != null) {
            attrmap.put(X509Principal.ST, state);
            order.add(X509Principal.ST);
        }

        if (country != null) {
            attrmap.put(X509Principal.C, country);
            order.add(X509Principal.C);
        }

        X509Principal issuerDN = new X509Principal(order, attrmap);

        // validity
        long curr = System.currentTimeMillis();
        long untill = curr + (long) validity * 24 * 60 * 60 * 1000;

        certgen.setNotBefore(new Date(curr));
        certgen.setNotAfter(new Date(untill));
        certgen.setIssuerDN(issuerDN);
        certgen.setSubjectDN(issuerDN);
        certgen.setPublicKey(publicKey);
        certgen.setSignatureAlgorithm(algorithm);
        certgen.setSerialNumber(new BigInteger(String.valueOf(curr)));

        // make certificate
        return certgen.generateX509Certificate(privateKey);
    }

    private void saveKeystore(char[] password) throws KeystoreException {
        try {
            BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(keystoreFile));
            keystore.store(out, password);
            out.flush();
            out.close();
            keystoreReadDate = System.currentTimeMillis();
        } catch (KeyStoreException e) {
            throw new KeystoreException("Unable to save keystore '" + keystoreName + "'", e);
        } catch (FileNotFoundException e) {
            throw new KeystoreException("Unable to save keystore '" + keystoreName + "'", e);
        } catch (IOException e) {
            throw new KeystoreException("Unable to save keystore '" + keystoreName + "'", e);
        } catch (NoSuchAlgorithmException e) {
            throw new KeystoreException("Unable to save keystore '" + keystoreName + "'", e);
        } catch (CertificateException e) {
            throw new KeystoreException("Unable to save keystore '" + keystoreName + "'", e);
        }
    }

}
TOP

Related Classes of org.apache.geronimo.security.keystore.FileKeystoreInstance

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.