mitm.common.security.keystore.jce.KeyStoreHibernate.java Source code

Java tutorial

Introduction

Here is the source code for mitm.common.security.keystore.jce.KeyStoreHibernate.java

Source

/*
 * Copyright (c) 2008-2011, Martijn Brinkers, Djigzo.
 * 
 * This file is part of Djigzo email encryption.
 *
 * Djigzo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License 
 * version 3, 19 November 2007 as published by the Free Software 
 * Foundation.
 *
 * Djigzo 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public 
 * License along with Djigzo. If not, see <http://www.gnu.org/licenses/>
 *
 * Additional permission under GNU AGPL version 3 section 7
 * 
 * If you modify this Program, or any covered work, by linking or 
 * combining it with aspectjrt.jar, aspectjweaver.jar, tyrex-1.0.3.jar, 
 * freemarker.jar, dom4j.jar, mx4j-jmx.jar, mx4j-tools.jar, 
 * spice-classman-1.0.jar, spice-loggerstore-0.5.jar, spice-salt-0.8.jar, 
 * spice-xmlpolicy-1.0.jar, saaj-api-1.3.jar, saaj-impl-1.3.jar, 
 * wsdl4j-1.6.1.jar (or modified versions of these libraries), 
 * containing parts covered by the terms of Eclipse Public License, 
 * tyrex license, freemarker license, dom4j license, mx4j license,
 * Spice Software License, Common Development and Distribution License
 * (CDDL), Common Public License (CPL) the licensors of this Program grant 
 * you additional permission to convey the resulting work.
 */
package mitm.common.security.keystore.jce;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.spec.InvalidKeySpecException;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import mitm.common.hibernate.DatabaseAction;
import mitm.common.hibernate.DatabaseActionExecutor;
import mitm.common.hibernate.DatabaseActionExecutorBuilder;
import mitm.common.hibernate.DatabaseException;
import mitm.common.hibernate.DatabaseVoidAction;
import mitm.common.hibernate.SessionManager;
import mitm.common.security.keystore.KeyStoreRuntimeException;
import mitm.common.security.keystore.dao.KeyStoreDAO;
import mitm.common.security.keystore.dao.KeyStoreDAOHibernate;
import mitm.common.security.keystore.hibernate.KeyStoreEntryHibernate;
import mitm.common.security.keystore.hibernate.SerializableKeyEntry;
import mitm.common.security.password.PBEncryption;

import org.apache.commons.collections.iterators.IteratorEnumeration;
import org.hibernate.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class KeyStoreHibernate extends KeyStoreSpi {
    private static final Logger logger = LoggerFactory.getLogger(KeyStoreHibernate.class);

    /*
     * The number of times a database action should be retried when a ConstraintViolation occurs
     */
    private final static int ACTION_RETRIES = 3;

    private final DatabaseActionExecutor databaseExecutor;

    private final PBEncryption encryptor;

    /**
     * Name of this store. Default when the name is not set.
     */
    private String storeName = "default";

    public KeyStoreHibernate(SessionManager sessionManager, PBEncryption encryptor) {
        this.databaseExecutor = DatabaseActionExecutorBuilder.createDatabaseActionExecutor(sessionManager);
        this.encryptor = encryptor;
    }

    @Override
    public Enumeration<String> engineAliases() throws KeyStoreRuntimeException {
        Enumeration<String> aliasesEnum = null;

        try {
            aliasesEnum = databaseExecutor.executeTransaction(new DatabaseAction<Enumeration<String>>() {
                @Override
                public Enumeration<String> doAction(Session session) {
                    return getAliasesAction(session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);
            /*
             * engineAliases cannot throw a checked exception so
             * we will throw a runtime exception
             */
            throw new KeyStoreRuntimeException(e);
        }

        return aliasesEnum;
    }

    @SuppressWarnings("unchecked")
    private Enumeration<String> getAliasesAction(Session session) {
        KeyStoreDAO dao = new KeyStoreDAOHibernate(storeName, session);

        List<String> aliases = dao.getAliases();

        return new IteratorEnumeration(aliases.iterator());
    }

    @Override
    public boolean engineContainsAlias(final String alias) throws KeyStoreRuntimeException {
        KeyStoreEntryHibernate entry;

        try {
            entry = databaseExecutor.executeTransaction(new DatabaseAction<KeyStoreEntryHibernate>() {
                @Override
                public KeyStoreEntryHibernate doAction(Session session) {
                    return getEntryByAliasAction(alias, session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);

            return entry != null;
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);
            /*
             * engineAliases cannot throw a checked exception so
             * we will throw a runtime exception
             */
            throw new KeyStoreRuntimeException(e);
        }
    }

    private KeyStoreEntryHibernate getEntryByAliasAction(String alias, Session session) {
        KeyStoreDAO dao = new KeyStoreDAOHibernate(storeName, session);

        KeyStoreEntryHibernate entry = dao.getEntryByAlias(alias);

        return entry;
    }

    @Override
    public void engineDeleteEntry(final String alias) throws KeyStoreException {
        try {
            databaseExecutor.executeTransaction(new DatabaseVoidAction() {
                @Override
                public void doAction(Session session) {
                    deleteEntryByAliasAction(alias, session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);

            throw new KeyStoreException(e);
        }
    }

    private void deleteEntryByAliasAction(String alias, Session session) {
        KeyStoreDAO dao = new KeyStoreDAOHibernate(storeName, session);

        KeyStoreEntryHibernate entry = dao.getEntryByAlias(alias);

        if (entry != null) {
            dao.delete(entry);
        }
    }

    @Override
    public Certificate engineGetCertificate(final String alias) throws KeyStoreRuntimeException {
        KeyStoreEntryHibernate entry;

        try {
            entry = databaseExecutor.executeTransaction(new DatabaseAction<KeyStoreEntryHibernate>() {
                @Override
                public KeyStoreEntryHibernate doAction(Session session) {
                    return getEntryByAliasAction(alias, session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);

            return entry != null ? entry.getCertificate() : null;
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);
            /*
             * engineAliases cannot throw a checked exception so
             * we will throw a runtime exception
             */
            throw new KeyStoreRuntimeException(e);
        }
    }

    @Override
    public String engineGetCertificateAlias(final Certificate certificate) throws KeyStoreRuntimeException {
        KeyStoreEntryHibernate entry;

        try {
            entry = databaseExecutor.executeTransaction(new DatabaseAction<KeyStoreEntryHibernate>() {
                @Override
                public KeyStoreEntryHibernate doAction(Session session) throws DatabaseException {
                    return getEntryByCertificateAction(certificate, session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);

            return entry != null ? entry.getKeyAlias() : null;
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);
            /*
             * engineAliases cannot throw a checked exception so
             * we will throw a runtime exception
             */
            throw new KeyStoreRuntimeException(e);
        }
    }

    private KeyStoreEntryHibernate getEntryByCertificateAction(Certificate certificate, Session session)
            throws DatabaseException {
        KeyStoreDAO dao = new KeyStoreDAOHibernate(storeName, session);

        try {
            KeyStoreEntryHibernate entry = dao.getEntryByCertificate(certificate);

            return entry;
        } catch (CertificateEncodingException e) {
            throw new DatabaseException(e);
        } catch (NoSuchAlgorithmException e) {
            throw new DatabaseException(e);
        } catch (NoSuchProviderException e) {
            throw new DatabaseException(e);
        }
    }

    @Override
    public Certificate[] engineGetCertificateChain(final String alias) throws KeyStoreRuntimeException {
        KeyStoreEntryHibernate entry;

        try {
            entry = databaseExecutor.executeTransaction(new DatabaseAction<KeyStoreEntryHibernate>() {
                @Override
                public KeyStoreEntryHibernate doAction(Session session) {
                    return getEntryByAliasAction(alias, session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);

            return entry != null ? entry.getChain() : null;
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);
            /*
             * engineAliases cannot throw a checked exception so
             * we will throw a runtime exception
             */
            throw new KeyStoreRuntimeException(e);
        }
    }

    @Override
    public Date engineGetCreationDate(final String alias) throws KeyStoreRuntimeException {
        KeyStoreEntryHibernate entry;

        try {
            entry = databaseExecutor.executeTransaction(new DatabaseAction<KeyStoreEntryHibernate>() {
                @Override
                public KeyStoreEntryHibernate doAction(Session session) {
                    return getEntryByAliasAction(alias, session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);

            return entry != null ? entry.getCreationDate() : null;
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);
            /*
             * engineAliases cannot throw a checked exception so
             * we will throw a runtime exception
             */
            throw new KeyStoreRuntimeException(e);
        }
    }

    @Override
    public Key engineGetKey(final String alias, char[] password)
            throws NoSuchAlgorithmException, UnrecoverableKeyException {
        KeyStoreEntryHibernate entry;

        try {
            entry = databaseExecutor.executeTransaction(new DatabaseAction<KeyStoreEntryHibernate>() {
                @Override
                public KeyStoreEntryHibernate doAction(Session session) {
                    return getEntryByAliasAction(alias, session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);

            if (entry == null) {
                return null;
            }

            byte[] serialized = entry.getEncodedKey();

            SerializableKeyEntry serializableKeyEntry = SerializableKeyEntry.deserialize(serialized);

            Key key;

            if (password != null) {
                key = serializableKeyEntry.getKey(password, encryptor);
            } else {
                key = serializableKeyEntry.getKey();
            }

            return key;
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);

            throw new UnrecoverableKeyException(e.getMessage());
        } catch (InvalidKeyException e) {
            logger.error("InvalidKeyException.", e);

            throw new UnrecoverableKeyException(e.getMessage());
        } catch (KeyStoreException e) {
            logger.error("KeyStoreException.", e);

            throw new UnrecoverableKeyException(e.getMessage());
        } catch (InvalidKeySpecException e) {
            logger.error("InvalidKeySpecException.", e);

            throw new UnrecoverableKeyException(e.getMessage());
        } catch (NoSuchProviderException e) {
            logger.error("NoSuchProviderException.", e);

            throw new UnrecoverableKeyException(e.getMessage());
        } catch (NoSuchPaddingException e) {
            logger.error("NoSuchPaddingException.", e);

            throw new UnrecoverableKeyException(e.getMessage());
        } catch (IllegalBlockSizeException e) {
            logger.error("IllegalBlockSizeException.", e);

            throw new UnrecoverableKeyException(e.getMessage());
        } catch (BadPaddingException e) {
            logger.error("BadPaddingException.", e);

            throw new UnrecoverableKeyException(e.getMessage());
        } catch (IOException e) {
            logger.error("IOException.", e);

            throw new UnrecoverableKeyException(e.getMessage());
        }
    }

    @Override
    public boolean engineIsCertificateEntry(final String alias) throws KeyStoreRuntimeException {
        KeyStoreEntryHibernate entry;

        try {
            entry = databaseExecutor.executeTransaction(new DatabaseAction<KeyStoreEntryHibernate>() {
                @Override
                public KeyStoreEntryHibernate doAction(Session session) {
                    return getEntryByAliasAction(alias, session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);

            if (entry == null) {
                return false;
            }

            return entry.getEncodedKey() == null;
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);
            /*
             * engineAliases cannot throw a checked exception so
             * we will throw a runtime exception
             */
            throw new KeyStoreRuntimeException(e);
        }
    }

    @Override
    public boolean engineIsKeyEntry(final String alias) throws KeyStoreRuntimeException {
        KeyStoreEntryHibernate entry;

        try {
            entry = databaseExecutor.executeTransaction(new DatabaseAction<KeyStoreEntryHibernate>() {
                @Override
                public KeyStoreEntryHibernate doAction(Session session) {
                    return getEntryByAliasAction(alias, session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);

            if (entry == null) {
                return false;
            }

            return entry.getEncodedKey() != null;
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);
            /*
             * engineAliases cannot throw a checked exception so
             * we will throw a runtime exception
             */
            throw new KeyStoreRuntimeException(e);
        }
    }

    @Override
    public void engineLoad(InputStream stream, char[] password)
            throws IOException, NoSuchAlgorithmException, CertificateException {
        /* not implemented */
    }

    @Override
    public void engineLoad(KeyStore.LoadStoreParameter loadStoreParameter)
            throws IOException, NoSuchAlgorithmException, CertificateException {
        if (loadStoreParameter != null) {
            if (!(loadStoreParameter instanceof DatabaseKeyStoreLoadStoreParameter)) {
                throw new IOException("loadStoreParameter must be an DatabaseKeyStoreLoadStoreParameter.");
            }

            DatabaseKeyStoreLoadStoreParameter params = (DatabaseKeyStoreLoadStoreParameter) loadStoreParameter;

            this.storeName = params.getStoreName();

            if (params.getSessionManager() != null) {
                this.databaseExecutor.setSessionManager(params.getSessionManager());
            }
        }
    }

    @Override
    public void engineSetCertificateEntry(final String alias, final Certificate certificate)
            throws KeyStoreException {
        try {
            databaseExecutor.executeTransaction(new DatabaseVoidAction() {
                @Override
                public void doAction(Session session) {
                    setCertificateEntryAction(alias, certificate, session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);

            throw new KeyStoreException(e);
        }
    }

    private void setCertificateEntryAction(String alias, Certificate certificate, Session session) {
        KeyStoreDAO dao = new KeyStoreDAOHibernate(storeName, session);

        KeyStoreEntryHibernate entry = dao.getEntryByAlias(alias);

        if (entry == null) {
            entry = new KeyStoreEntryHibernate(storeName, alias, new Date());
            dao.makePersistent(entry);
        }

        entry.setEncodedKey(null);
        entry.setChain(null);
        entry.setCertificate(certificate);
    }

    @Override
    public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException {
        throw new KeyStoreException("Not yet supported.");
    }

    @Override
    public void engineSetKeyEntry(final String alias, final Key key, final char[] password,
            final Certificate[] chain) throws KeyStoreException {
        try {
            databaseExecutor.executeTransaction(new DatabaseVoidAction() {
                @Override
                public void doAction(Session session) throws DatabaseException {
                    setKeyEntryAction(alias, key, password, chain, session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);

            throw new KeyStoreException(e);
        }
    }

    private void setKeyEntryAction(String alias, Key key, char[] password, Certificate[] chain, Session session)
            throws DatabaseException {
        KeyStoreDAO dao = new KeyStoreDAOHibernate(storeName, session);

        SerializableKeyEntry serializable;
        try {
            serializable = new SerializableKeyEntry(key, password, encryptor);

            Certificate certificate = null;

            if (chain != null && chain.length > 0) {
                certificate = chain[0];
            }

            KeyStoreEntryHibernate entry = dao.getEntryByAlias(alias);

            if (entry == null) {
                entry = new KeyStoreEntryHibernate(storeName, alias, new Date());
                dao.makePersistent(entry);
            }

            entry.setEncodedKey(serializable.serialize());
            entry.setChain(chain);
            entry.setCertificate(certificate);
        } catch (InvalidKeyException e) {
            logger.error("InvalidKeyException.", e);

            throw new DatabaseException(e);
        } catch (InvalidKeySpecException e) {
            logger.error("InvalidKeySpecException.", e);

            throw new DatabaseException(e);
        } catch (NoSuchAlgorithmException e) {
            logger.error("NoSuchAlgorithmException.", e);

            throw new DatabaseException(e);
        } catch (NoSuchProviderException e) {
            logger.error("NoSuchProviderException.", e);

            throw new DatabaseException(e);
        } catch (NoSuchPaddingException e) {
            logger.error("NoSuchPaddingException.", e);

            throw new DatabaseException(e);
        } catch (IllegalBlockSizeException e) {
            logger.error("IllegalBlockSizeException.", e);

            throw new DatabaseException(e);
        } catch (BadPaddingException e) {
            logger.error("BadPaddingException.", e);

            throw new DatabaseException(e);
        } catch (IOException e) {
            logger.error("IOException.", e);

            throw new DatabaseException(e);
        }
    }

    @Override
    public int engineSize() throws KeyStoreRuntimeException {
        try {
            int size = databaseExecutor.executeTransaction(new DatabaseAction<Integer>() {
                @Override
                public Integer doAction(Session session) {
                    return getSizeAction(session);
                }
            }, ACTION_RETRIES /* retry on a ConstraintViolationException */);

            return size;
        } catch (DatabaseException e) {
            logger.error("Database exception.", e);
            /*
             * engineAliases cannot throw a checked exception so
             * we will throw a runtime exception
             */
            throw new KeyStoreRuntimeException(e);
        }
    }

    private int getSizeAction(Session session) {
        KeyStoreDAO dao = new KeyStoreDAOHibernate(storeName, session);

        return dao.getEntryCount().intValue();
    }

    @Override
    public void engineStore(OutputStream stream, char[] password)
            throws IOException, NoSuchAlgorithmException, CertificateException {
        throw new IOException("Not yet supported.");
    }
}