Package org.apache.geronimo.security.keystore

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

/**
*
* Copyright 2005 The Apache Software Foundation
*
*  Licensed 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.File;
import java.io.FileInputStream;
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.PrivateKey;
import java.security.PublicKey;
import java.security.SignatureException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.j2ee.j2eeobjectnames.NameFactory;
import org.apache.geronimo.kernel.Kernel;
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.util.jce.X509Principal;
import org.apache.geronimo.util.jce.X509V1CertificateGenerator;

/**
* 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: 409817 $ $Date: 2006-05-27 09:56:38 +0200 (Sat, 27 May 2006) $
*/
public class FileKeystoreInstance implements KeystoreInstance, GBeanLifecycle {
    private static final Log log = LogFactory.getLog(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 char[] keystorePassword; // Used to "unlock" the keystore for other services
    private Map keyPasswords = new HashMap();
    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 keyPasswords, Kernel kernel, AbstractName abstractName) {
        this.serverInfo = serverInfo;
        this.keystorePath = keystorePath;
        this.keystoreName = keystoreName;
        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 String getKeystoreName() {
        return keystoreName;
    }

    public boolean unlockKeystore(char[] password) {
        //todo: test whether password is correct and if not return false
        try {
            kernel.setAttribute(abstractName, "keystorePassword", password == null ? null : new String(password));
        } catch (Exception e) {
            throw (IllegalStateException)new IllegalStateException("Unable to set attribute keystorePassword on myself!").initCause(e);
        }
        return true;
    }

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

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

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

    public String[] listPrivateKeys(char[] storePassword) {
        if(!isLoaded(storePassword)) {
            if(!loadKeystoreData(storePassword)) {
                return null;
            }
        }
        return (String[]) privateKeys.toArray(new String[privateKeys.size()]);
    }

    public boolean unlockPrivateKey(String alias, char[] password) throws KeystoreIsLocked {
        if(isKeystoreLocked()) {
            throw new KeystoreIsLocked("Keystore '"+keystoreName+"' is locked!");
        }
        //todo: test whether password is correct and if not return false
        keyPasswords.put(alias, password);
        storePasswords();
        return true;
    }

    public String[] getUnlockedKeys() throws KeystoreIsLocked {
        if(isKeystoreLocked()) {
            throw new KeystoreIsLocked("Keystore '"+keystoreName+"' is locked; please unlock it in the console.");
        }
        if(keystore == null || keystoreReadDate < keystoreFile.lastModified()) {
            loadKeystoreData(keystorePassword);
        }
        return (String[]) keyPasswords.keySet().toArray(new String[keyPasswords.size()]);
    }

    public boolean isTrustStore() throws KeystoreIsLocked {
        if(isKeystoreLocked()) {
            throw new KeystoreIsLocked("Keystore '"+keystoreName+"' is locked; please unlock it in the console.");
        }
        if(keystore == null || keystoreReadDate < keystoreFile.lastModified()) {
            loadKeystoreData(keystorePassword);
        }
        return trustCerts.size() > 0;
    }

    public void lockPrivateKey(String alias) {
        keyPasswords.remove(alias);
        storePasswords();
    }

    private void storePasswords() {
        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(entry.getValue());
        }
        try {
            kernel.setAttribute(abstractName, "keyPasswords", buf.length() == 0 ? null : buf.toString());
        } catch (Exception e) {
            log.error("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) {
        if(!isLoaded(storePassword)) {
            if(!loadKeystoreData(storePassword)) {
                return null;
            }
        }
        return (String[]) trustCerts.toArray(new String[trustCerts.size()]);
    }

    public Certificate getCertificate(String alias, char[] storePassword) {
        if(!isLoaded(storePassword)) {
            if(!loadKeystoreData(storePassword)) {
                return null;
            }
        }
        try {
            return keystore.getCertificate(alias);
        } catch (KeyStoreException e) {
            log.error("Unable to read certificate from keystore", e);
        }
        return null;
    }

    public boolean importTrustCertificate(Certificate cert, String alias, char[] storePassword) {
        if(!isLoaded(storePassword)) {
            if(!loadKeystoreData(storePassword)) {
                return false;
            }
        }
        try {
            keystore.setCertificateEntry(alias, cert);
            trustCerts.add(alias);
            return saveKeystore(storePassword);
        } catch (KeyStoreException e) {
            log.error("Unable to import certificate", e);
        }
        return false;
    }

    public boolean 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) {
        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);
            return saveKeystore(storePassword);
        } catch (SignatureException e) {
            log.error("Unable to generate key pair", e);
        } catch (InvalidKeyException e) {
            log.error("Unable to generate key pair", e);
        } catch (KeyStoreException e) {
            log.error("Unable to generate key pair", e);
        } catch (NoSuchAlgorithmException e) {
            log.error("Unable to generate key pair", e);
        }
        return false;
    }

    public KeyManager[] getKeyManager(String algorithm, String alias) throws NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException, KeystoreIsLocked {
        if(isKeystoreLocked()) {
            throw new KeystoreIsLocked("Keystore '"+keystoreName+"' is locked; please unlock it in the console.");
        }
        if(keystore == null || keystoreReadDate < keystoreFile.lastModified()) {
            loadKeystoreData(keystorePassword);
        }
        KeyManagerFactory keyFactory = KeyManagerFactory.getInstance(algorithm);
        keyFactory.init(keystore, (char[]) keyPasswords.get(alias));
        return keyFactory.getKeyManagers();
    }

    public TrustManager[] getTrustManager(String algorithm) throws KeyStoreException, NoSuchAlgorithmException, KeystoreIsLocked {
        if(isKeystoreLocked()) {
            throw new KeystoreIsLocked("Keystore '"+keystoreName+"' is locked; please unlock it in the console.");
        }
        if(keystore == null || keystoreReadDate < keystoreFile.lastModified()) {
            loadKeystoreData(keystorePassword);
        }
        TrustManagerFactory trustFactory = TrustManagerFactory.getInstance(algorithm);
        trustFactory.init(keystore);
        return trustFactory.getTrustManagers();
    }

    private boolean saveKeystore(char[] password) {
        try {
            BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(keystoreFile));
            keystore.store(out, password);
            out.flush();
            out.close();
            keystoreReadDate = System.currentTimeMillis();
            return true;
        } catch (KeyStoreException e) {
            log.error("Unable to save keystore", e);
        } catch (IOException e) {
            log.error("Unable to save keystore", e);
        } catch (NoSuchAlgorithmException e) {
            log.error("Unable to save keystore", e);
        } catch (CertificateException e) {
            log.error("Unable to save keystore", e);
        }
        return false;
    }

    public static final GBeanInfo GBEAN_INFO;

    static {
        GBeanInfoBuilder infoFactory = GBeanInfoBuilder.createStatic(FileKeystoreInstance.class, NameFactory.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("keyPasswords", String.class, true, true);
        infoFactory.addAttribute("kernel", Kernel.class, false);
        infoFactory.addAttribute("abstractName", AbstractName.class, false);
        infoFactory.addReference("ServerInfo", ServerInfo.class, NameFactory.GERONIMO_SERVICE);
        infoFactory.addInterface(KeystoreInstance.class);
        infoFactory.setConstructor(new String[]{"ServerInfo","keystorePath", "keystoreName", "keystorePassword", "keyPasswords", "kernel", "abstractName"});

        GBEAN_INFO = infoFactory.getBeanInfo();
    }

    public static GBeanInfo getGBeanInfo() {
        return GBEAN_INFO;
    }

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

    private boolean loadKeystoreData(char[] password) {
        try {
            keystoreReadDate = System.currentTimeMillis();
            privateKeys.clear();
            trustCerts.clear();
            if(keystore == null) {
                keystore = KeyStore.getInstance(JKS);
            }
            InputStream in = new BufferedInputStream(new FileInputStream(keystoreFile));
            keystore.load(in, password);
            in.close();
            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);
                }
            }
            return true;
        } catch (KeyStoreException e) {
            log.error("Unable to open keystore with provided password", e);
        } catch (IOException e) {
            log.error("Unable to open keystore with provided password", e);
        } catch (NoSuchAlgorithmException e) {
            log.error("Unable to open keystore with provided password", e);
        } catch (CertificateException e) {
            log.error("Unable to open keystore with provided password", e);
        }
        return false;
    }

    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 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);
    }
}
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.