Package org.ejbca.core.ejb.ca.caadmin

Source Code of org.ejbca.core.ejb.ca.caadmin.CAAdminSessionBean

/*************************************************************************
*                                                                       *
*  EJBCA: The OpenSource Certificate Authority                          *
*                                                                       *
*  This software is free software; you can redistribute it and/or       *
*  modify it under the terms of the GNU Lesser General Public           *
*  License as published by the Free Software Foundation; either         *
*  version 2.1 of the License, or any later version.                    *
*                                                                       *
*  See terms of license at gnu.org.                                     *
*                                                                       *
*************************************************************************/

package org.ejbca.core.ejb.ca.caadmin;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.CertPathValidatorException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateExpiredException;
import java.security.cert.CertificateNotYetValidException;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;

import javax.annotation.PostConstruct;
import javax.ejb.CreateException;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.bouncycastle.jce.PKCS10CertificationRequest;
import org.bouncycastle.jce.X509KeyUsage;
import org.bouncycastle.util.encoders.Hex;
import org.cesecore.core.ejb.ca.crl.CrlCreateSessionLocal;
import org.cesecore.core.ejb.ca.store.CertificateProfileSessionLocal;
import org.cesecore.core.ejb.log.LogSessionLocal;
import org.ejbca.config.EjbcaConfiguration;
import org.ejbca.config.GlobalConfiguration;
import org.ejbca.core.EjbcaException;
import org.ejbca.core.ErrorCode;
import org.ejbca.core.ejb.JndiHelper;
import org.ejbca.core.ejb.approval.ApprovalSessionLocal;
import org.ejbca.core.ejb.authorization.AuthorizationSessionLocal;
import org.ejbca.core.ejb.ca.publisher.PublisherSessionLocal;
import org.ejbca.core.ejb.ca.store.CertificateStoreSessionLocal;
import org.ejbca.core.model.AlgorithmConstants;
import org.ejbca.core.model.InternalResources;
import org.ejbca.core.model.SecConst;
import org.ejbca.core.model.approval.ApprovalDataVO;
import org.ejbca.core.model.approval.ApprovalException;
import org.ejbca.core.model.approval.ApprovalExecutorUtil;
import org.ejbca.core.model.approval.ApprovalOveradableClassName;
import org.ejbca.core.model.approval.WaitingForApprovalException;
import org.ejbca.core.model.approval.approvalrequests.ActivateCATokenApprovalRequest;
import org.ejbca.core.model.authorization.AccessRulesConstants;
import org.ejbca.core.model.authorization.AuthorizationDeniedException;
import org.ejbca.core.model.authorization.Authorizer;
import org.ejbca.core.model.ca.NotSupportedException;
import org.ejbca.core.model.ca.caadmin.CA;
import org.ejbca.core.model.ca.caadmin.CACacheManager;
import org.ejbca.core.model.ca.caadmin.CADoesntExistsException;
import org.ejbca.core.model.ca.caadmin.CAExistsException;
import org.ejbca.core.model.ca.caadmin.CAInfo;
import org.ejbca.core.model.ca.caadmin.CVCCA;
import org.ejbca.core.model.ca.caadmin.CVCCAInfo;
import org.ejbca.core.model.ca.caadmin.IllegalKeyStoreException;
import org.ejbca.core.model.ca.caadmin.X509CA;
import org.ejbca.core.model.ca.caadmin.X509CAInfo;
import org.ejbca.core.model.ca.caadmin.extendedcaservices.CmsCAServiceInfo;
import org.ejbca.core.model.ca.caadmin.extendedcaservices.ExtendedCAServiceInfo;
import org.ejbca.core.model.ca.caadmin.extendedcaservices.ExtendedCAServiceNotActiveException;
import org.ejbca.core.model.ca.caadmin.extendedcaservices.ExtendedCAServiceRequest;
import org.ejbca.core.model.ca.caadmin.extendedcaservices.ExtendedCAServiceRequestException;
import org.ejbca.core.model.ca.caadmin.extendedcaservices.ExtendedCAServiceResponse;
import org.ejbca.core.model.ca.caadmin.extendedcaservices.IllegalExtendedCAServiceRequestException;
import org.ejbca.core.model.ca.caadmin.extendedcaservices.OCSPCAServiceInfo;
import org.ejbca.core.model.ca.caadmin.extendedcaservices.XKMSCAServiceInfo;
import org.ejbca.core.model.ca.catoken.CATokenAuthenticationFailedException;
import org.ejbca.core.model.ca.catoken.CATokenConstants;
import org.ejbca.core.model.ca.catoken.CATokenContainer;
import org.ejbca.core.model.ca.catoken.CATokenContainerImpl;
import org.ejbca.core.model.ca.catoken.CATokenInfo;
import org.ejbca.core.model.ca.catoken.CATokenManager;
import org.ejbca.core.model.ca.catoken.CATokenOfflineException;
import org.ejbca.core.model.ca.catoken.HardCATokenInfo;
import org.ejbca.core.model.ca.catoken.ICAToken;
import org.ejbca.core.model.ca.catoken.NullCATokenInfo;
import org.ejbca.core.model.ca.catoken.SoftCATokenInfo;
import org.ejbca.core.model.ca.certificateprofiles.CertificatePolicy;
import org.ejbca.core.model.ca.certificateprofiles.CertificateProfile;
import org.ejbca.core.model.ca.crl.RevokedCertInfo;
import org.ejbca.core.model.ca.store.CertificateInfo;
import org.ejbca.core.model.log.Admin;
import org.ejbca.core.model.log.LogConstants;
import org.ejbca.core.model.ra.ExtendedInformation;
import org.ejbca.core.model.ra.UserDataVO;
import org.ejbca.core.model.util.AlgorithmTools;
import org.ejbca.core.protocol.IRequestMessage;
import org.ejbca.core.protocol.IResponseMessage;
import org.ejbca.core.protocol.PKCS10RequestMessage;
import org.ejbca.core.protocol.X509ResponseMessage;
import org.ejbca.core.protocol.certificatestore.CertificateCacheFactory;
import org.ejbca.cvc.AuthorizationRoleEnum;
import org.ejbca.cvc.CardVerifiableCertificate;
import org.ejbca.util.Base64;
import org.ejbca.util.CertTools;
import org.ejbca.util.CryptoProviderTools;
import org.ejbca.util.SimpleTime;
import org.ejbca.util.StringTools;
import org.ejbca.util.keystore.KeyTools;

/**
* Administrates and manages CAs in EJBCA system.
*
* @version $Id: CAAdminSessionBean.java 11634 2011-03-30 09:49:31Z jeklund $
*/
@Stateless(mappedName = JndiHelper.APP_JNDI_PREFIX + "CAAdminSessionRemote")
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class CAAdminSessionBean implements CAAdminSessionLocal, CAAdminSessionRemote {

    private static final long serialVersionUID = 1L;
    private static final Logger log = Logger.getLogger(CAAdminSessionBean.class);

    @PersistenceContext(unitName="ejbca")
    private EntityManager entityManager;

    @EJB
    private LogSessionLocal logSession;
    @EJB
    private AuthorizationSessionLocal authorizationSession;
    @EJB
    private CaSessionLocal caSession;
    @EJB
    private CertificateProfileSessionLocal certificateProfileSession;
    @EJB
    private CertificateStoreSessionLocal certificateStoreSession;
    @EJB
    private CrlCreateSessionLocal crlCreateSession;
    @EJB
    private PublisherSessionLocal publisherSession;
    @EJB
    private ApprovalSessionLocal approvalSession;

    /** Internal localization of logs and errors */
    private static final InternalResources intres = InternalResources.getInstance();

    @PostConstruct
    public void postConstruct() {
        CryptoProviderTools.installBCProvider();
    }

    @Override
    public void initializeAndUpgradeCAs(Admin admin) {
      Collection<CAData> result = CAData.findAll(entityManager);
      Iterator<CAData> iter = result.iterator();
      while (iter.hasNext()) {
        CAData cadata = iter.next();
        String caname = cadata.getName();
        try {
          cadata.upgradeCA();
          log.info("Initialized CA: " + caname + ", with expire time: " + new Date(cadata.getExpireTime()));
        } catch (UnsupportedEncodingException e) {
          log.error("UnsupportedEncodingException trying to load CA with name: " + caname, e);
        } catch (IllegalKeyStoreException e) {
          log.error("IllegalKeyStoreException trying to load CA with name: " + caname, e);
        }
      }
    }

    @Override
    public void createCA(Admin admin, CAInfo cainfo) throws CAExistsException, AuthorizationDeniedException, CATokenOfflineException,
            CATokenAuthenticationFailedException {
      if (log.isTraceEnabled()) {
        log.trace(">createCA: "+cainfo.getName());
      }
        int castatus = SecConst.CA_OFFLINE;
        // Check that administrator has superadminstrator rights.
        if(!authorizationSession.isAuthorizedNoLog(admin, "/super_administrator")) {
            String msg = intres.getLocalizedMessage("caadmin.notauthorizedtocreateca", "create", cainfo.getName());
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_NOTAUTHORIZEDTORESOURCE,
                    msg);
            throw new AuthorizationDeniedException(msg);
        }
        // Check that CA doesn't already exists
        int caid = cainfo.getCAId();
        if (caid >= 0 && caid <= CAInfo.SPECIALCAIDBORDER) {
          String msg = intres.getLocalizedMessage("caadmin.wrongcaid", Integer.valueOf(caid));
          logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg);
          throw new CAExistsException(msg);
        }
        if (CAData.findById(entityManager, Integer.valueOf(caid)) != null) {
          String msg = intres.getLocalizedMessage("caadmin.caexistsid", Integer.valueOf(caid));
          logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg);
          throw new CAExistsException(msg);
        }
        if (CAData.findByName(entityManager, cainfo.getName()) != null) {
          String msg = intres.getLocalizedMessage("caadmin.caexistsname", cainfo.getName());
          logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg);
          throw new CAExistsException(msg);
        }
        // Create CAToken
        CATokenInfo catokeninfo = cainfo.getCATokenInfo();
        CATokenContainer catoken = new CATokenContainerImpl(catokeninfo, cainfo.getCAId());
        String authCode = catokeninfo.getAuthenticationCode();
        authCode = getDefaultKeyStorePassIfSWAndEmpty(authCode, catokeninfo);
        if (catokeninfo instanceof SoftCATokenInfo) {
            try {
                // There are two ways to get the authentication code:
                // 1. The user provided one when creating the CA on the create
                // CA page
                // 2. We use the system default password
                boolean renew = false;
                catoken.generateKeys(authCode, renew, true);
            } catch (Exception e) {
                String msg = intres.getLocalizedMessage("caadmin.errorcreatetoken");
                logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg, e);
                throw new EJBException(e);
            }
        }
        try {
            catoken.activate(authCode);
        } catch (CATokenAuthenticationFailedException ctaf) {
            String msg = intres.getLocalizedMessage("caadmin.errorcreatetokenpin");
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg, ctaf);
            throw ctaf;
        } catch (CATokenOfflineException ctoe) {
            String msg = intres.getLocalizedMessage("error.catokenoffline", cainfo.getName());
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg, ctoe);
            throw ctoe;
        }

        // Create CA
        CA ca = null;
        // The certificate profile used for the CAs certificate
        CertificateProfile certprofile = certificateProfileSession.getCertificateProfile(admin, cainfo.getCertificateProfileId());
        // AltName is not implemented for all CA types
        String caAltName = null;
        // X509 CA is the normal type of CA
        if (cainfo instanceof X509CAInfo) {
            log.info("Creating an X509 CA");
            X509CAInfo x509cainfo = (X509CAInfo) cainfo;
            // Create X509CA
            ca = new X509CA(x509cainfo);
            X509CA x509ca = (X509CA) ca;
            ca.setCAToken(catoken);

            // getCertificateProfile
            if ((x509cainfo.getPolicies() != null) && (x509cainfo.getPolicies().size() > 0)) {
                certprofile.setUseCertificatePolicies(true);
                certprofile.setCertificatePolicies(x509cainfo.getPolicies());
            } else if (certprofile.getUseCertificatePolicies()) {
                x509ca.setPolicies(certprofile.getCertificatePolicies());
            }
            caAltName = x509cainfo.getSubjectAltName();
        } else {
            // CVC CA is a special type of CA for EAC electronic passports
            log.info("Creating a CVC CA");
            CVCCAInfo cvccainfo = (CVCCAInfo) cainfo;
            // Create CVCCA
            ca = new CVCCA(cvccainfo);
            ca.setCAToken(catoken);
        }

        // Certificate chain
        Collection<Certificate> certificatechain = null;
        String sequence = catoken.getCATokenInfo().getKeySequence(); // get from CAtoken to make sure it is fresh
        if (cainfo.getSignedBy() == CAInfo.SELFSIGNED) {
            try {
                // create selfsigned certificate
                Certificate cacertificate = null;

                log.debug("CAAdminSessionBean : " + cainfo.getSubjectDN());

                UserDataVO cadata = new UserDataVO("nobody", cainfo.getSubjectDN(), cainfo.getSubjectDN().hashCode(), caAltName, null, 0, 0, 0, cainfo
                        .getCertificateProfileId(), null, null, 0, 0, null);

                cacertificate = ca.generateCertificate(cadata, catoken.getPublicKey(SecConst.CAKEYPURPOSE_CERTSIGN), -1, cainfo.getValidity(), certprofile,
                        sequence);

                log.debug("CAAdminSessionBean : " + CertTools.getSubjectDN(cacertificate));

                // Build Certificate Chain
                certificatechain = new ArrayList<Certificate>();
                certificatechain.add(cacertificate);

                // set status to active
                castatus = SecConst.CA_ACTIVE;
            } catch (CATokenOfflineException e) {
                String msg = intres.getLocalizedMessage("error.catokenoffline", cainfo.getName());
                logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg, e);
                throw e;
            } catch (Exception fe) {
                String msg = intres.getLocalizedMessage("caadmin.errorcreateca", cainfo.getName());
                logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg, fe);
                throw new EJBException(fe);
            }
        }
        if (cainfo.getSignedBy() == CAInfo.SIGNEDBYEXTERNALCA) {
            certificatechain = new ArrayList<Certificate>();
            // set status to waiting certificate response.
            castatus = SecConst.CA_WAITING_CERTIFICATE_RESPONSE;
        }

        if (cainfo.getSignedBy() > CAInfo.SPECIALCAIDBORDER || cainfo.getSignedBy() < 0) {
            // Create CA signed by other internal CA.
            try {
              CAData signcadata = CAData.findByIdOrThrow(entityManager, Integer.valueOf(cainfo.getSignedBy()));
                CA signca = signcadata.getCA();
                // Check that the signer is valid
                checkSignerValidity(admin, signcadata);
                // Create CA certificate
                Certificate cacertificate = null;

                UserDataVO cadata = new UserDataVO("nobody", cainfo.getSubjectDN(), cainfo.getSubjectDN().hashCode(), caAltName, null, 0, 0, 0, cainfo
                        .getCertificateProfileId(), null, null, 0, 0, null);

                cacertificate = signca.generateCertificate(cadata, catoken.getPublicKey(SecConst.CAKEYPURPOSE_CERTSIGN), -1, cainfo.getValidity(), certprofile,
                        sequence);

                // Build Certificate Chain
                Collection<Certificate> rootcachain = signca.getCertificateChain();
                certificatechain = new ArrayList<Certificate>();
                certificatechain.add(cacertificate);
                certificatechain.addAll(rootcachain);
                // set status to active
                castatus = SecConst.CA_ACTIVE;
            } catch (CATokenOfflineException e) {
                String msg = intres.getLocalizedMessage("error.catokenoffline", cainfo.getName());
                logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg, e);
                throw e;
            } catch (Exception fe) {
                String msg = intres.getLocalizedMessage("caadmin.errorcreateca", cainfo.getName());
                logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg, fe);
                throw new EJBException(fe);
            }
        }

        // Set Certificate Chain
        ca.setCertificateChain(certificatechain);

        // Publish CA certificates.
        publishCACertificate(admin, ca.getCertificateChain(), ca.getCRLPublishers(), ca.getSubjectDN());

        if (castatus == SecConst.CA_ACTIVE) {
            // activate External CA Services
            activateAndPublishExternalCAServices(admin, cainfo.getExtendedCAServiceInfos(), ca);
        }
        // Store CA in database.
        try {
          entityManager.persist(new CAData(cainfo.getSubjectDN(), cainfo.getName(), castatus, ca));
            if (castatus == SecConst.CA_ACTIVE) {
                // create initial CRL
                crlCreateSession.createCRLs(admin, ca, cainfo);
            }
            String msg = intres.getLocalizedMessage("caadmin.createdca", cainfo.getName(), Integer.valueOf(castatus));
            logSession.log(admin, ca.getCAId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CACREATED, msg);
        } catch (RuntimeException e) {
            String msg = intres.getLocalizedMessage("caadmin.errorcreateca", cainfo.getName());
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg);
            throw e;
        }
        // Update local OCSP's CA certificate cache
        CertificateCacheFactory.getInstance(certificateStoreSession).forceReload();
      if (log.isTraceEnabled()) {
        log.trace("<createCA: "+cainfo.getName());
      }
    }

    @Override
    public void editCA(Admin admin, CAInfo cainfo) throws AuthorizationDeniedException {
        boolean xkmsrenewcert = false;
        boolean cmsrenewcert = false;

        // Check authorization
        if(!authorizationSession.isAuthorizedNoLog(admin, "/super_administrator")) {
            String msg = intres.getLocalizedMessage("caadmin.notauthorizedtoeditca", cainfo.getName());
            logSession.log(admin, cainfo.getCAId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_NOTAUTHORIZEDTORESOURCE,
                    msg);
            throw new AuthorizationDeniedException(msg);
        }

        // Check if extended service certificates are about to be renewed.
        Iterator<ExtendedCAServiceInfo> iter = cainfo.getExtendedCAServiceInfos().iterator();
        while (iter.hasNext()) {
          ExtendedCAServiceInfo next = iter.next();
            // No OCSP Certificate exists that can be renewed.
            if (next instanceof XKMSCAServiceInfo) {
                xkmsrenewcert = ((XKMSCAServiceInfo) next).getRenewFlag();
            } else if (next instanceof CmsCAServiceInfo) {
                cmsrenewcert = ((CmsCAServiceInfo) next).getRenewFlag();
            }
        }

        // Get CA from database
        try {
          CAData cadata = CAData.findByIdOrThrow(entityManager, Integer.valueOf(cainfo.getCAId()));
            CA ca = cadata.getCA();

            // Update CA values
            ca.updateCA(cainfo);
            // Store CA in database
            cadata.setCA(ca);
            // Try to activate the CA token after we have edited the CA
            try {
                CATokenContainer catoken = ca.getCAToken();
                CATokenInfo catokeninfo = cainfo.getCATokenInfo();
                String authCode = catokeninfo.getAuthenticationCode();
                String keystorepass = getDefaultKeyStorePassIfSWAndEmpty(authCode, catokeninfo);
                if (keystorepass != null) {
                    catoken.activate(keystorepass);
                } else {
                    log.debug("Not trying to activate CAToken after editing, authCode == null.");
                }
            } catch (CATokenAuthenticationFailedException ctaf) {
                String msg = intres.getLocalizedMessage("caadmin.errorcreatetokenpin");
                logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, ctaf);
            } catch (CATokenOfflineException ctoe) {
                String msg = intres.getLocalizedMessage("error.catokenoffline", cainfo.getName());
                logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, ctoe);
            }
            // No OCSP Certificate exists that can be renewed.
            if (xkmsrenewcert) {
                XKMSCAServiceInfo info = (XKMSCAServiceInfo) ca.getExtendedCAServiceInfo(ExtendedCAServiceInfo.TYPE_XKMSEXTENDEDSERVICE);
                Certificate xkmscert = (Certificate) info.getXKMSSignerCertificatePath().get(0);
                ArrayList<Certificate> xkmscertificate = new ArrayList<Certificate>();
                xkmscertificate.add(xkmscert);
                // Publish the extended service certificate, but only for active
                // services
                if ((info.getStatus() == ExtendedCAServiceInfo.STATUS_ACTIVE) && (!xkmscertificate.isEmpty())) {
                    publishCACertificate(admin, xkmscertificate, ca.getCRLPublishers(), ca.getSubjectDN());
                }
            }
            if (cmsrenewcert) {
                CmsCAServiceInfo info = (CmsCAServiceInfo) ca.getExtendedCAServiceInfo(ExtendedCAServiceInfo.TYPE_CMSEXTENDEDSERVICE);
                Certificate cmscert = (Certificate) info.getCertificatePath().get(0);
                ArrayList<Certificate> cmscertificate = new ArrayList<Certificate>();
                cmscertificate.add(cmscert);
                // Publish the extended service certificate, but only for active
                // services
                if ((info.getStatus() == ExtendedCAServiceInfo.STATUS_ACTIVE) && (!cmscertificate.isEmpty())) {
                    publishCACertificate(admin, cmscertificate, ca.getCRLPublishers(), ca.getSubjectDN());
                }
            }
            // Log Action
            String msg = intres.getLocalizedMessage("caadmin.editedca", cainfo.getName());
            logSession.log(admin, cainfo.getCAId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CAEDITED, msg);
        } catch (Exception fe) {
            String msg = intres.getLocalizedMessage("caadmin.erroreditca", cainfo.getName());
            log.error(msg, fe);
            logSession.log(admin, cainfo.getCAId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, fe);
            throw new EJBException(fe);
        }
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    @Override
    public CAInfo getCAInfoOrThrowException(Admin admin, String name) throws CADoesntExistsException {
        return caSession.getCA(admin, name).getCAInfo();
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    @Override
    public CAInfo getCAInfo(Admin admin, String name) {
        CAInfo caInfo = null;
        try {
            caInfo = getCAInfoOrThrowException(admin, name);
        } catch (CADoesntExistsException e) {
            // NOPMD ignore, we want to return null and getCAInfoOrThrowException already logged
          // that we could not find it
        }
        return caInfo;
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    @Override
    public CAInfo getCAInfoOrThrowException(Admin admin, int caid) throws CADoesntExistsException {
        return getCAInfoOrThrowException(admin, caid, false);
    }

    /**
     * Internal method that get CA info, and optionally performs a sign test
     * with the CAs test signing key.
     *
     * If doSignTest is true, and the CA is active and the CA is included in
     * healthcheck (cainfo.getIncludeInHealthCheck()), a signature with the test
     * keys is performed to set the CA Token status correctly.
     *
     * @param admin
     *            administrator performing this action
     * @param caid
     *            numerical id of CA (subjectDN.hashCode()) that we search for
     * @param doSignTest
     *            true if a test signature should be performed, false if only
     *            the status from token info is checked. Should normally be set
     *            to false.
     * @return CAInfo value object, never null
     * @throws CADoesntExistsException
     *             if CA with caid does not exist or admin is not authorized to CA
     */
    private CAInfo getCAInfoOrThrowException(Admin admin, int caid, boolean doSignTest) throws CADoesntExistsException {
        if (!authorizedToCA(admin, caid)) {
            if (log.isDebugEnabled()) {
                log.debug("Admin (" + admin.toString() + ") is not authorized to CA: " + caid);
            }
            String msg = intres.getLocalizedMessage("caadmin.canotexistsid", Integer.valueOf(caid));
            throw new CADoesntExistsException(msg);
        }
        CAInfo cainfo = null;
        try {
            CA ca = caSession.getCA(admin, caid);      
            cainfo = ca.getCAInfo();
            int status = cainfo.getStatus();
            boolean includeInHealthCheck = cainfo.getIncludeInHealthCheck();
            int tokenstatus = ICAToken.STATUS_OFFLINE;
            if (doSignTest && status == SecConst.CA_ACTIVE && includeInHealthCheck) {
                // Only do a real test signature if the CA is supposed to be
                // active and if it is included in healthchecking
                // Otherwise we will only waste resources
                if (log.isDebugEnabled()) {
                    log.debug("Making test signature with CAs token. CA=" + ca.getName() + ", doSignTest=" + doSignTest + ", CA status=" + status
                            + ", includeInHealthCheck=" + includeInHealthCheck);
                }
                CATokenContainer catoken = ca.getCAToken();
                tokenstatus = catoken.getCATokenInfo().getCATokenStatus();
            } else {
                // if (log.isDebugEnabled()) {
                // log.debug("Not making test signature with CAs token. doSignTest="+doSignTest+", CA status="+status+", includeInHealthCheck="+includeInHealthCheck);
                // }
                tokenstatus = cainfo.getCATokenInfo().getCATokenStatus();
            }
            // Set a possible new status in the info value object
            cainfo.getCATokenInfo().setCATokenStatus(tokenstatus);
        } catch (CADoesntExistsException ce) {
            // Just re-throw, getCAInternal has already logged that the CA does
            // not exist
            throw ce;
        } catch (Exception e) {
            String msg = intres.getLocalizedMessage("caadmin.errorgetcainfo", Integer.valueOf(caid));
            log.error(msg, e);
            throw new EJBException(e);
        }
        return cainfo;
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    @Override
    public CAInfo getCAInfo(Admin admin, int caid) {
        // No sign test for the standard method
        return getCAInfo(admin, caid, false);
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    @Override
    public CAInfo getCAInfo(Admin admin, int caid, boolean doSignTest) {
        CAInfo caInfo = null;
        try {
            caInfo = getCAInfoOrThrowException(admin, caid, doSignTest);
        } catch (CADoesntExistsException e) {
            // NOPMD ignore, we want to return null and getCAInfoOrThrowException already logged
          // that we could not find it
        }
        return caInfo;
    }

    @Override
    public void verifyExistenceOfCA(int caid) throws CADoesntExistsException {
      // TODO: Test if "SELECT a.caId FROM CAData a WHERE a.caId=:caId" improves performance
      CAData.findByIdOrThrow(entityManager, Integer.valueOf(caid));
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    @Override
    public HashMap<Integer,String> getCAIdToNameMap(Admin admin) {
        HashMap<Integer, String> returnval = new HashMap<Integer, String>();
        Collection<CAData> result = CAData.findAll(entityManager);
        Iterator<CAData> iter = result.iterator();
        while (iter.hasNext()) {
          CAData cadata = iter.next();
          returnval.put(cadata.getCaId(), cadata.getName());
        }
        return returnval;
    }

    @Override
    public byte[] makeRequest(Admin admin, int caid, Collection<?> cachainin, boolean regenerateKeys, boolean usenextkey, boolean activatekey, String keystorepass)
            throws CADoesntExistsException, AuthorizationDeniedException, CertPathValidatorException, CATokenOfflineException,
            CATokenAuthenticationFailedException {
        if (log.isTraceEnabled()) {
            log.trace(">makeRequest: " + caid + ", regenerateKeys=" + regenerateKeys + ", usenextkey=" + usenextkey + ", activatekey=" + activatekey);
        }
        byte[] returnval = null;
        // Check authorization
        try {
           
            if(!authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.REGULAR_RENEWCA)) {
                Authorizer.throwAuthorizationException(admin, AccessRulesConstants.REGULAR_RENEWCA, null);
            }
            if (!authorizedToCA(admin, caid)) {
                throw new AuthorizationDeniedException("Not authorized to CA");
            }
        } catch (AuthorizationDeniedException e) {
            String msg = intres.getLocalizedMessage("caadmin.notauthorizedtocertreq", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_NOTAUTHORIZEDTORESOURCE, msg, e);
            throw new AuthorizationDeniedException(msg);
        }

        // Get CA info.
        CAData cadata = null;
        try {
          cadata = CAData.findByIdOrThrow(entityManager, Integer.valueOf(caid));
            CA ca = cadata.getCA();
            String caname = ca.getName();

            Collection<Certificate> chain = null;
            if ((cachainin != null) && (cachainin.size() > 0)) {
                chain = CertTools.createCertChain(cachainin);
                log.debug("Setting request certificate chain of size: " + chain.size());
                ca.setRequestCertificateChain(chain);
            } else {
                log.debug("Empty request certificate chain parameter.");
                // create empty list if input was null
                chain = new ArrayList<Certificate>();
            }
            // AR+ patch to make SPOC independent of external CVCA certificates for automatic renewals
            // i.e. if we don't pass a CA certificate as parameter we try to find a suitable CA certificate in the database, among existing CAs
            // (can be a simple imported CA-certificate of external CA)
            if (chain.isEmpty() &&
              ca.getCAType() == CAInfo.CATYPE_CVC &&
                ca.getSignedBy() == CAInfo.SIGNEDBYEXTERNALCA &&
                ca.getStatus() == SecConst.CA_ACTIVE){
              CardVerifiableCertificate dvcert = (CardVerifiableCertificate)ca.getCACertificate();
          String ca_ref = dvcert.getCVCertificate().getCertificateBody().getAuthorityReference().getConcatenated();
              log.debug("DV renewal missing CVCA cert, try finding CA for:"+ ca_ref);
            Iterator<Integer> cas = caSession.getAvailableCAs(admin).iterator();
            while (cas.hasNext()){
              CA cvca = caSession.getCA(admin,cas.next());
              if (cvca.getCAType() == CAInfo.CATYPE_CVC && cvca.getSignedBy() == CAInfo.SELFSIGNED){
                CardVerifiableCertificate cvccert = (CardVerifiableCertificate)cvca.getCACertificate();
                if (ca_ref.equals (cvccert.getCVCertificate().getCertificateBody().getHolderReference().getConcatenated())){
                        log.debug("Added missing CVCA to rewnewal request: "+ cvca.getName());
                  chain.add(cvccert);
                  break;
                }
              }
             }
            if (chain.isEmpty ()){
                  log.info("Failed finding suitable CVCA, forgot to import it?");
            }
            }
            // AR-
           
            // Generate new certificate request.
            String signAlg = "SHA1WithRSA"; // Default algorithm
            CATokenInfo tinfo = ca.getCAInfo().getCATokenInfo();
            if (tinfo != null) {
                signAlg = tinfo.getSignatureAlgorithm();
            }
            log.debug("Using signing algorithm: " + signAlg + " for the CSR.");

            CATokenContainer caToken = ca.getCAToken();
            if (regenerateKeys) {
                log.debug("Generating new keys.");
                keystorepass = getDefaultKeyStorePassIfSWAndEmpty(keystorepass, caToken.getCATokenInfo());
                caToken.generateKeys(keystorepass, true, activatekey);
                ca.setCAToken(caToken);
                // In order to generate a certificate with this keystore we must
                // make sure it is activated
                ca.getCAToken().activate(keystorepass);
            }
            // The CA certificate signing this request is the first in the
            // certificate chain
            Iterator<Certificate> iter = chain.iterator();
            Certificate cacert = null;
            if (iter.hasNext()) {
                cacert = (Certificate) iter.next();
            }
            // If we don't set status to waiting we want to use the next
            // signature key pair
            int keyPurpose = SecConst.CAKEYPURPOSE_CERTSIGN;
            boolean usepreviouskey = true; // for creating an authenticated
            // request we sign it with the
            // previous key
            if (usenextkey || (regenerateKeys && !activatekey)) {
                keyPurpose = SecConst.CAKEYPURPOSE_CERTSIGN_NEXT;
                usepreviouskey = false; // for creating an authenticated request
                // we sign it with the current key,
                // which will be the previous once we
                // activate the new key
            }
            log.debug("Creating certificate request with key purpose: " + keyPurpose);
            byte[] request = ca.createRequest(null, signAlg, cacert, keyPurpose);
            if (ca.getCAType() == CAInfo.CATYPE_CVC) {
                // If this is a CVC CA renewal request, we need to sign it to
                // make an authenticated request
                // The CVC CAs current signing certificate will always be the
                // right one, because it is the "previous" signing certificate
                // until we have imported a new one
                // as response to the request we create here.
                boolean createlinkcert = false; // this is not a link
                // certificate, and never can be
                // If we try to sign an initial request there will be no CA
                // certificate and signRequest will return the same as we pass
                // in, i.e. do nothing.
                try {
                    returnval = ca.signRequest(request, usepreviouskey, createlinkcert);
                } catch (RuntimeException e) {
                    Throwable cause = e.getCause();
                    // If this is an IllegalKeyException we it's possible that
                    // we did not have a previous key, then just skip and make
                    // it authenticated
                    // and return the request message as is
                    if (cause instanceof InvalidKeyException) {
                        log.info("Failed to sign CVC request with previous key (does it exist?). Returning unauthenticated request.", e);
                        returnval = request;
                    } else {
                        throw e;
                    }
                }
            } else {
                returnval = request;
            }

            // Set statuses if it should be set.
            if ((regenerateKeys || usenextkey) && activatekey) {
                cadata.setStatus(SecConst.CA_WAITING_CERTIFICATE_RESPONSE);
                ca.setStatus(SecConst.CA_WAITING_CERTIFICATE_RESPONSE);
            }

            cadata.setCA(ca);
            // Log information about the event
            String msg = intres.getLocalizedMessage("caadmin.certreqcreated", caname, Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CAEDITED, msg);
        } catch (CertPathValidatorException e) {
            String msg = intres.getLocalizedMessage("caadmin.errorcertreq", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
            throw e;
        } catch (CATokenOfflineException e) {
            String msg = intres.getLocalizedMessage("caadmin.errorcertreq", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
            throw e;
        } catch (CATokenAuthenticationFailedException e) {
            String msg = intres.getLocalizedMessage("caadmin.errorcertreq", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
            throw e;
        } catch (Exception e) {
            String msg = intres.getLocalizedMessage("caadmin.errorcertreq", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
            throw new EJBException(e);
        }

        String msg = intres.getLocalizedMessage("caadmin.certreqcreated", Integer.valueOf(caid));
        logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CAEDITED, msg);
        if (log.isTraceEnabled()) {
            log.trace("<makeRequest: " + caid);
        }
        return returnval;
    }

    @Override
    public byte[] signRequest(Admin admin, int caid, byte[] request, boolean usepreviouskey, boolean createlinkcert) throws AuthorizationDeniedException,
            CADoesntExistsException, CATokenOfflineException {
       if(!authorizationSession.isAuthorizedNoLog(admin, "/super_administrator")) {
            String msg = intres.getLocalizedMessage("caadmin.notauthorizedtocertreq", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_NOTAUTHORIZEDTORESOURCE, msg);
            throw new AuthorizationDeniedException(msg);
        }
        byte[] returnval = null;
        String caname = "" + caid;
        CAData signedbydata = CAData.findByIdOrThrow(entityManager, Integer.valueOf(caid));
        try {
            caname = signedbydata.getName();
            CA signedbyCA = signedbydata.getCA();
            returnval = signedbyCA.signRequest(request, usepreviouskey, createlinkcert);
            String msg = intres.getLocalizedMessage("caadmin.certreqsigned", caname);
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_SIGNEDREQUEST, msg);
        } catch (Exception e) {
            String msg = intres.getLocalizedMessage("caadmin.errorcertreqsign", caname);
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_SIGNEDREQUEST, msg, e);
            throw new EJBException(e);
        }
        return returnval;
    }

    @Override
    public void receiveResponse(Admin admin, int caid, IResponseMessage responsemessage, Collection<?> cachain, String tokenAuthenticationCode)
            throws AuthorizationDeniedException, CertPathValidatorException, EjbcaException {
        Certificate cacert = null;
        // Check authorization
        try {
            if(!authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.REGULAR_RENEWCA)) {
                Authorizer.throwAuthorizationException(admin, AccessRulesConstants.REGULAR_RENEWCA, null);
            }
            if (!authorizedToCA(admin, caid)) {
                throw new AuthorizationDeniedException("Not authorized to CA");
            }
        } catch (AuthorizationDeniedException e) {
            String msg = intres.getLocalizedMessage("caadmin.notauthorizedtocertresp", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_NOTAUTHORIZEDTORESOURCE, msg, e);
            throw new AuthorizationDeniedException(msg);
        }

        // Get CA info.
        CAData cadata = CAData.findById(entityManager, Integer.valueOf(caid));
        if (cadata == null) {
            String msg = intres.getLocalizedMessage("caadmin.errorcertresp", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg);
            throw new EjbcaException(msg);
        }
        try {
            CA ca = cadata.getCA();
            try {
                if (responsemessage instanceof X509ResponseMessage) {
                    cacert = ((X509ResponseMessage) responsemessage).getCertificate();
                } else {
                    String msg = intres.getLocalizedMessage("caadmin.errorcertrespillegalmsg", responsemessage != null ? responsemessage.getClass().getName()
                            : "null");
                    logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg);
                    throw new EjbcaException(msg);
                }

                // If signed by external CA, process the received certificate
                // and store it, activating the CA
                if (ca.getSignedBy() == CAInfo.SIGNEDBYEXTERNALCA) {
                    // Check that CA DN is equal to the certificate response.
                    if (!CertTools.getSubjectDN(cacert).equals(CertTools.stringToBCDNString(ca.getSubjectDN()))) {
                        String msg = intres.getLocalizedMessage("caadmin.errorcertrespwrongdn", CertTools.getSubjectDN(cacert), ca.getSubjectDN());
                        logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg);
                        throw new EjbcaException(msg);
                    }

                    ArrayList<Certificate> tmpchain = new ArrayList<Certificate>();
                    tmpchain.add(cacert);
                    // If we have a chain given as parameter, we will use that.
                    // If no parameter is given we assume that the request chain
                    // was stored when the request was created.
                    Collection<Certificate> reqchain = null;
                    if ((cachain != null) && (cachain.size() > 0)) {
                        reqchain = CertTools.createCertChain(cachain);
                        log.debug("Using CA certificate chain from parameter of size: " + reqchain.size());
                    } else {
                        reqchain = ca.getRequestCertificateChain();
                        log.debug("Using pre-stored CA certificate chain.");
                        if (reqchain == null) {
                            String msg = intres.getLocalizedMessage("caadmin.errornorequestchain", caid, ca.getSubjectDN());
                            log.info(msg);
                            throw new CertPathValidatorException(msg);
                        }
                    }
                    log.debug("Picked up request certificate chain of size: " + reqchain.size());
                    tmpchain.addAll(reqchain);
                    Collection<Certificate> chain = CertTools.createCertChain(tmpchain);
                    log.debug("Storing certificate chain of size: " + chain.size());
                    // Before importing the certificate we want to make sure
                    // that the public key matches the CAs private key
                    CATokenContainer catoken = ca.getCAToken();
                    // If it is a DV certificate signed by a CVCA, enrich the
                    // public key for EC parameters from the CVCA's certificate
                    PublicKey pk = cacert.getPublicKey();
                    if (StringUtils.equals(cacert.getType(), "CVC")) {
                        if (pk.getAlgorithm().equals("ECDSA")) {
                            CardVerifiableCertificate cvccert = (CardVerifiableCertificate) cacert;
                            try {
                                if ((cvccert.getCVCertificate().getCertificateBody().getAuthorizationTemplate().getAuthorizationField().getRole() == AuthorizationRoleEnum.DV_D)
                                        || (cvccert.getCVCertificate().getCertificateBody().getAuthorizationTemplate().getAuthorizationField().getRole() == AuthorizationRoleEnum.DV_F)) {
                                    log.debug("Enriching DV public key with EC parameters from CVCA");
                                    Certificate cvcacert = (Certificate) reqchain.iterator().next();
                                    pk = KeyTools.getECPublicKeyWithParams(pk, cvcacert.getPublicKey());
                                }
                            } catch (InvalidKeySpecException e) {
                                log.debug("Strange CVCA certificate that we can't get the key from, continuing anyway...", e);
                            } catch (NoSuchFieldException e) {
                                log.debug("Strange DV certificate with no AutheorizationRole, continuing anyway...", e);
                            }
                        } else {
                            log.debug("Key is not ECDSA, don't try to enrich with EC parameters.");
                        }
                    } else {
                        log.debug("Cert is not CVC, no need to enrich with EC parameters.");
                    }
                    try {
                        KeyTools.testKey(catoken.getPrivateKey(SecConst.CAKEYPURPOSE_CERTSIGN), pk, catoken.getProvider());
                    } catch (Exception e1) {
                        log.debug("The received certificate response does not match the CAs private signing key for purpose CAKEYPURPOSE_CERTSIGN, trying CAKEYPURPOSE_CERTSIGN_NEXT...");
                        if (e1 instanceof InvalidKeyException) {
                            log.trace(e1);
                        } else {
                            // If it's not invalid key, we want to see more of
                            // the error
                            log.debug("Error: ", e1);
                        }
                        try {
                            KeyTools.testKey(catoken.getPrivateKey(SecConst.CAKEYPURPOSE_CERTSIGN_NEXT), pk, catoken.getProvider());
                            // This was OK, so we must also activate the next
                            // signing key when importing this certificate
                            catoken.activateNextSignKey(tokenAuthenticationCode);
                            ca.setCAToken(catoken);
                            // In order to generate a certificate with this
                            // keystore we must make sure it is activated
                            ca.getCAToken().activate(tokenAuthenticationCode);
                        } catch (Exception e2) {
                            log.debug("The received certificate response does not match the CAs private signing key for purpose CAKEYPURPOSE_CERTSIGN_NEXT either, giving up.");
                            if ((e2 instanceof InvalidKeyException) || (e2 instanceof IllegalArgumentException)) {
                                log.trace(e2);
                            } else {
                                // If it's not invalid key or missing authentication code,
                                // we want to see more of the error
                                log.debug("Error: ", e2);
                            }
                            throw new EjbcaException(ErrorCode.INVALID_KEY, e2);
                        }
                    }
                    ca.setCertificateChain(chain);

                    // Publish CA Certificate
                    publishCACertificate(admin, chain, ca.getCRLPublishers(), ca.getSubjectDN());

                    // Set status to active, so we can sign certificates for the
                    // external services below.
                    cadata.setStatus(SecConst.CA_ACTIVE);
                    ca.setStatus(SecConst.CA_ACTIVE);

                    // activate External CA Services
                    Iterator<Integer> iter = ca.getExternalCAServiceTypes().iterator();
                    while (iter.hasNext()) {
                        int type = iter.next().intValue();
                        try {
                            ca.initExternalService(type, ca);
                            ArrayList<Certificate> extcacertificate = new ArrayList<Certificate>();
                            ExtendedCAServiceInfo info = null;
                            if (type == ExtendedCAServiceInfo.TYPE_OCSPEXTENDEDSERVICE) {
                                info = (OCSPCAServiceInfo) ca.getExtendedCAServiceInfo(ExtendedCAServiceInfo.TYPE_OCSPEXTENDEDSERVICE);
                                // The OCSP certificate is the same as the
                                // singing certificate
                            }
                            if (type == ExtendedCAServiceInfo.TYPE_XKMSEXTENDEDSERVICE) {
                                info = ca.getExtendedCAServiceInfo(ExtendedCAServiceInfo.TYPE_XKMSEXTENDEDSERVICE);
                                extcacertificate.add(((XKMSCAServiceInfo) info).getXKMSSignerCertificatePath().get(0));
                            }
                            if (type == ExtendedCAServiceInfo.TYPE_CMSEXTENDEDSERVICE) {
                                info = ca.getExtendedCAServiceInfo(ExtendedCAServiceInfo.TYPE_CMSEXTENDEDSERVICE);
                                extcacertificate.add(((CmsCAServiceInfo) info).getCertificatePath().get(0));
                            }
                            // Publish the extended service certificate, but
                            // only for active services
                            if ((info != null) && (info.getStatus() == ExtendedCAServiceInfo.STATUS_ACTIVE) && (!extcacertificate.isEmpty())) {
                                publishCACertificate(admin, extcacertificate, ca.getCRLPublishers(), ca.getSubjectDN());
                            }
                        } catch (CATokenOfflineException e) {
                            String msg = intres.getLocalizedMessage("caadmin.errorcreatecaservice", Integer.valueOf(caid));
                            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null,
                                    LogConstants.EVENT_ERROR_CACREATED, msg, e);
                            throw e;
                        } catch (Exception fe) {
                            String msg = intres.getLocalizedMessage("caadmin.errorcreatecaservice", Integer.valueOf(caid));
                            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null,
                                    LogConstants.EVENT_ERROR_CACREATED, msg, fe);
                            throw new EJBException(fe);
                        }
                    }

                    // Set expire time
                    ca.setExpireTime(CertTools.getNotAfter(cacert));
                    cadata.setExpireTime(CertTools.getNotAfter(cacert).getTime());
                    // Save CA
                    cadata.setCA(ca);

                    // Create initial CRL
                    crlCreateSession.createCRLs(admin, ca, ca.getCAInfo());
                } else {
                    String msg = intres.getLocalizedMessage("caadmin.errorcreatecaservice", Integer.valueOf(caid));
                    // Cannot create certificate request for internal CA
                    logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg);
                    throw new EjbcaException(msg);
                }

            } catch (CATokenOfflineException e) {
                String msg = intres.getLocalizedMessage("caadmin.errorcertresp", Integer.valueOf(caid));
                logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
                throw e;
            } catch (CertificateEncodingException e) {
                String msg = intres.getLocalizedMessage("caadmin.errorcertresp", Integer.valueOf(caid));
                logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
                throw new EjbcaException(e.getMessage());
            } catch (CertificateException e) {
                String msg = intres.getLocalizedMessage("caadmin.errorcertresp", Integer.valueOf(caid));
                logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
                throw new EjbcaException(e.getMessage());
            } catch (IOException e) {
                String msg = intres.getLocalizedMessage("caadmin.errorcertresp", Integer.valueOf(caid));
                logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
                throw new EjbcaException(e.getMessage());
            } catch (InvalidAlgorithmParameterException e) {
                String msg = intres.getLocalizedMessage("caadmin.errorcertresp", Integer.valueOf(caid));
                logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
                throw new EjbcaException(e.getMessage());
            } catch (NoSuchAlgorithmException e) {
                String msg = intres.getLocalizedMessage("caadmin.errorcertresp", Integer.valueOf(caid));
                logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
                throw new EjbcaException(e.getMessage());
            } catch (NoSuchProviderException e) {
                String msg = intres.getLocalizedMessage("caadmin.errorcertresp", Integer.valueOf(caid));
                logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
                throw new EjbcaException(e.getMessage());
            }
        } catch (UnsupportedEncodingException e) {
            String msg = intres.getLocalizedMessage("caadmin.errorcertresp", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
            throw new EjbcaException(e.getMessage());
        }

        String msg = intres.getLocalizedMessage("caadmin.certrespreceived", Integer.valueOf(caid));
        logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CAEDITED, msg);
    }

    @Override
    public IResponseMessage processRequest(Admin admin, CAInfo cainfo, IRequestMessage requestmessage) throws CAExistsException, CADoesntExistsException,
            AuthorizationDeniedException, CATokenOfflineException {
        final CA ca;
        Collection<Certificate> certchain = null;
        IResponseMessage returnval = null;
        // check authorization
        if(!authorizationSession.isAuthorizedNoLog(admin, "/super_administrator")) {
            String msg = intres.getLocalizedMessage("caadmin.notauthorizedtocertresp", cainfo.getName());
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_NOTAUTHORIZEDTORESOURCE,
                    msg);
            throw new AuthorizationDeniedException(msg);
        }

        // Check that CA doesn't already exists
        CAData oldcadata = null;
        int caid = cainfo.getCAId();
        if (caid >= 0 && caid <= CAInfo.SPECIALCAIDBORDER) {
          String msg = intres.getLocalizedMessage("caadmin.errorcaexists", cainfo.getName());
          logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg);
          throw new CAExistsException(msg);
        }
        oldcadata = CAData.findById(entityManager, Integer.valueOf(caid));
        // If it did not exist with a certain DN (caid) perhaps a CA with the
        // same CA name exists?
        if (oldcadata == null) {
          oldcadata = CAData.findByName(entityManager, cainfo.getName());
        }
        boolean processinternalca = false;
        if (oldcadata != null) {
            // If we find an already existing CA, there is a good chance that we
            // should throw an exception
            // Saying that the CA already exists.
            // However, if we have the same DN, and give the same name, we
            // simply assume that the admin actually wants
            // to treat an internal CA as an external CA, perhaps there is
            // different HSMs connected for root CA and sub CA?
            if (log.isDebugEnabled()) {
                log.debug("Old castatus=" + oldcadata.getStatus() + ", oldcaid=" + oldcadata.getCaId().intValue() + ", caid=" + cainfo.getCAId()
                        + ", oldcaname=" + oldcadata.getName() + ", name=" + cainfo.getName());
            }
            if (((oldcadata.getStatus() == SecConst.CA_WAITING_CERTIFICATE_RESPONSE) || (oldcadata.getStatus() == SecConst.CA_ACTIVE) || (oldcadata.getStatus() == SecConst.CA_EXTERNAL))
                    && (oldcadata.getCaId().intValue() == cainfo.getCAId()) && (oldcadata.getName().equals(cainfo.getName()))) {
                // Yes, we have all the same DN, CAName and the old CA is either
                // waiting for a certificate response or is active
                // (new CA or active CA that we want to renew)
                // or it is an external CA that we want to issue a new
                // certificate to
                processinternalca = true;
                if (oldcadata.getStatus() == SecConst.CA_EXTERNAL) {
                    log.debug("Renewing an external CA.");
                } else {
                    log.debug("Processing an internal CA, as an external.");
                }
            } else {
                String msg = intres.getLocalizedMessage("caadmin.errorcaexists", cainfo.getName());
                log.info(msg);
                throw new CAExistsException(msg);
            }
        }

        // get signing CA
        if (cainfo.getSignedBy() > CAInfo.SPECIALCAIDBORDER || cainfo.getSignedBy() < 0) {
            try {
              CAData signcadata = CAData.findByIdOrThrow(entityManager, Integer.valueOf(cainfo.getSignedBy()));
                CA signca = signcadata.getCA();
                try {
                    // Check that the signer is valid
                    checkSignerValidity(admin, signcadata);

                    // Get public key from request
                    PublicKey publickey = requestmessage.getRequestPublicKey();

                    // Create cacertificate
                    Certificate cacertificate = null;
                    String subjectAltName = null;
                    if (cainfo instanceof X509CAInfo) {
                        subjectAltName = ((X509CAInfo) cainfo).getSubjectAltName();
                    }
                    UserDataVO cadata = new UserDataVO("nobody", cainfo.getSubjectDN(), cainfo.getSubjectDN().hashCode(), subjectAltName, null, 0, 0, 0, cainfo
                            .getCertificateProfileId(), null, null, 0, 0, null);
                    // We can pass the PKCS10 request message as extra
                    // parameters
                    if (requestmessage instanceof PKCS10RequestMessage) {
                        ExtendedInformation extInfo = new ExtendedInformation();
                        PKCS10CertificationRequest pkcs10 = ((PKCS10RequestMessage) requestmessage).getCertificationRequest();
                        extInfo.setCustomData(ExtendedInformation.CUSTOM_PKCS10, new String(Base64.encode(pkcs10.getEncoded())));
                        cadata.setExtendedinformation(extInfo);
                    }
                    CertificateProfile certprofile = certificateProfileSession.getCertificateProfile(admin, cainfo.getCertificateProfileId());
                    String sequence = null;
                    byte[] ki = requestmessage.getRequestKeyInfo();
                    if ((ki != null) && (ki.length > 0)) {
                        sequence = new String(ki);
                    }
                    cacertificate = signca.generateCertificate(cadata, publickey, -1, cainfo.getValidity(), certprofile, sequence);
                    // X509ResponseMessage works for both X509 CAs and CVC CAs
                    // here...pure luck? I don't think so!
                    returnval = new X509ResponseMessage();
                    returnval.setCertificate(cacertificate);

                    // Build Certificate Chain
                    Collection<Certificate> rootcachain = signca.getCertificateChain();
                    certchain = new ArrayList<Certificate>();
                    certchain.add(cacertificate);
                    certchain.addAll(rootcachain);

                    if (!processinternalca) {
                        // If this is an internal CA, we don't create it and set
                        // a NULL token, since the CA is already created
                        if (cainfo instanceof X509CAInfo) {
                            log.info("Creating a X509 CA (process request)");
                            ca = new X509CA((X509CAInfo) cainfo);
                        } else if (cainfo instanceof CVCCAInfo) {
                            // CVC CA is a special type of CA for EAC electronic
                            // passports
                            log.info("Creating a CVC CA (process request)");
                            CVCCAInfo cvccainfo = (CVCCAInfo) cainfo;
                            // Create CVCCA
                            ca = new CVCCA(cvccainfo);
                        } else {
                            ca = null;
                        }
                        ca.setCertificateChain(certchain);
                        CATokenContainer token = new CATokenContainerImpl(new NullCATokenInfo(), cainfo.getCAId());
                        ca.setCAToken(token);

                        // set status to active
                        entityManager.persist(new CAData(cainfo.getSubjectDN(), cainfo.getName(), SecConst.CA_EXTERNAL, ca));
                        //cadatahome.create(cainfo.getSubjectDN(), cainfo.getName(), SecConst.CA_EXTERNAL, ca);
                    } else {
                        if (oldcadata.getStatus() == SecConst.CA_EXTERNAL) {
                            // If it is an external CA we will not import the
                            // certificate later on here, so we want to
                            // update the CA in this instance with the new
                            // certificate so it is visible
                            ca = oldcadata.getCA();
                            ca.setCertificateChain(certchain);
                            if (log.isDebugEnabled()) {
                                log.debug("Storing new certificate chain for external CA " + cainfo.getName() + ", CA token type: "
                                        + ca.getCAToken().getCATokenType());
                            }
                            oldcadata.setCA(ca);
                        } else {
                            // If it is an internal CA so we are "simulating"
                            // signing a real external CA we don't do anything
                            // because that CA is waiting to import a
                            // certificate
                            if (log.isDebugEnabled()) {
                                log.debug("Not storing new certificate chain or updating CA for internal CA, simulating external: " + cainfo.getName());
                            }
                            ca = null;
                        }
                    }
                    // Publish CA certificates.
                    publishCACertificate(admin, certchain, signca.getCRLPublishers(), ca != null ? ca.getSubjectDN() : null);
                    // External CAs will not have any CRLs in this system, so we don't have to try to publish any CRLs
                } catch (CATokenOfflineException e) {
                    String msg = intres.getLocalizedMessage("caadmin.errorprocess", cainfo.getName());
                    log.error(msg, e);
                    logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
                    throw e;
                }
            } catch (Exception e) {
                String msg = intres.getLocalizedMessage("caadmin.errorprocess", cainfo.getName());
                log.error(msg, e);
                logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
                throw new EJBException(e);
            }

        }

        if (certchain != null) {
            String msg = intres.getLocalizedMessage("caadmin.processedca", cainfo.getName());
            logSession.log(admin, cainfo.getCAId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CAEDITED, msg);
        } else {
            String msg = intres.getLocalizedMessage("caadmin.errorprocess", cainfo.getName());
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg);
        }
        return returnval;
    }

    @Override
    public void importCACertificate(Admin admin, String caname, Collection<Certificate> certificates) throws CreateException {
        Certificate caCertificate = (Certificate) certificates.iterator().next();
        CA ca = null;
        CAInfo cainfo = null;

        // Parameters common for both X509 and CVC CAs
        ArrayList<Integer> approvalsettings = new ArrayList<Integer>();
        int numofreqapprovals = 1;
        boolean finishuser = false;
        Collection<ExtendedCAServiceInfo> extendedcaserviceinfos = new ArrayList<ExtendedCAServiceInfo>();
        ArrayList<Integer> crlpublishers = new ArrayList<Integer>();
        long crlperiod = 0 * SimpleTime.MILLISECONDS_PER_HOUR;
        long crlIssueInterval = 0 * SimpleTime.MILLISECONDS_PER_HOUR;
        long crlOverlapTime = 10 * SimpleTime.MILLISECONDS_PER_HOUR;
        long deltacrlperiod = 0 * SimpleTime.MILLISECONDS_PER_HOUR;
        int certprofileid = CertTools.isSelfSigned(caCertificate) ? SecConst.CERTPROFILE_FIXED_ROOTCA : SecConst.CERTPROFILE_FIXED_SUBCA;
        String subjectdn = CertTools.getSubjectDN(caCertificate);
        int validity = 0;
        int signedby = CertTools.isSelfSigned(caCertificate) ? CAInfo.SELFSIGNED : CAInfo.SIGNEDBYEXTERNALCA;
        String description = "CA created by certificate import.";
        log.info("Preparing to import of CA with Subject DN " + subjectdn);

        if (caCertificate instanceof X509Certificate) {
            X509Certificate x509CaCertificate = (X509Certificate) caCertificate;
            String subjectaltname = null;
            try {
                subjectaltname = CertTools.getSubjectAlternativeName(x509CaCertificate);
            } catch (CertificateParsingException e) {
                log.error("", e);
            } catch (IOException e) {
                log.error("", e);
            }

            // Process certificate policies.
            ArrayList<CertificatePolicy> policies = new ArrayList<CertificatePolicy>();
            CertificateProfile certprof = certificateProfileSession.getCertificateProfile(admin, certprofileid);
            if (certprof.getCertificatePolicies() != null && certprof.getCertificatePolicies().size() > 0) {
                policies.addAll(certprof.getCertificatePolicies());
            }

            boolean useauthoritykeyidentifier = false;
            boolean authoritykeyidentifiercritical = false;

            boolean usecrlnumber = false;
            boolean crlnumbercritical = false;

            boolean useutf8policytext = false;
            boolean useprintablestringsubjectdn = false;
            boolean useldapdnorder = true; // Default value
            boolean usecrldistpointoncrl = false;
            boolean crldistpointoncrlcritical = false;

            cainfo = new X509CAInfo(subjectdn, caname, SecConst.CA_EXTERNAL, new Date(), subjectaltname, certprofileid, validity, CertTools
                    .getNotAfter(x509CaCertificate), CAInfo.CATYPE_X509, signedby, null, null, description, -1, null, policies, crlperiod, crlIssueInterval,
                    crlOverlapTime, deltacrlperiod, crlpublishers, useauthoritykeyidentifier, authoritykeyidentifiercritical, usecrlnumber, crlnumbercritical,
                    "", "", "", "", finishuser, extendedcaserviceinfos, useutf8policytext, approvalsettings, numofreqapprovals, useprintablestringsubjectdn,
                    useldapdnorder, usecrldistpointoncrl, crldistpointoncrlcritical, false, true, // isDoEnforceUniquePublicKeys
                    true, // isDoEnforceUniqueDistinguishedName
                    false, // isDoEnforceUniqueSubjectDNSerialnumber
                    true, // useCertReqHistory
                    true, // useUserStorage
                    true, // useCertificateStorage
                    null //cmpRaAuthSecret
            );
        } else if (StringUtils.equals(caCertificate.getType(), "CVC")) {
            cainfo = new CVCCAInfo(subjectdn, caname, 0, new Date(), certprofileid, validity, null, CAInfo.CATYPE_CVC, signedby, null, null, description, -1,
                    null, crlperiod, crlIssueInterval, crlOverlapTime, deltacrlperiod, crlpublishers, finishuser, extendedcaserviceinfos, approvalsettings,
                    numofreqapprovals, false, true, // isDoEnforceUniquePublicKeys
                    true, // isDoEnforceUniqueDistinguishedName
                    false, // isDoEnforceUniqueSubjectDNSerialnumber
                    true, // useCertReqHistory
                    true, // useUserStorage
                    true // useCertificateStorage
            );
        }
        if (cainfo instanceof X509CAInfo) {
            log.info("Creating a X509 CA (process request)");
            ca = new X509CA((X509CAInfo) cainfo);
        } else if (cainfo instanceof CVCCAInfo) {
            // CVC CA is a special type of CA for EAC electronic passports
            log.info("Creating a CVC CA (process request)");
            CVCCAInfo cvccainfo = (CVCCAInfo) cainfo;
            ca = new CVCCA(cvccainfo);
        }
        ca.setCertificateChain(certificates);
        CATokenContainer token = new CATokenContainerImpl(new NullCATokenInfo(), cainfo.getCAId());
        ca.setCAToken(token);
        // set status to active
        entityManager.persist(new CAData(cainfo.getSubjectDN(), cainfo.getName(), SecConst.CA_EXTERNAL, ca));
        // Publish CA certificates.
        publishCACertificate(admin, certificates, null, ca.getSubjectDN());
    }

    @Override
    public void initExternalCAService(Admin admin, int caid, ExtendedCAServiceInfo info) throws CATokenOfflineException, AuthorizationDeniedException,
            CADoesntExistsException, UnsupportedEncodingException, IllegalKeyStoreException {
        // check authorization
        if(!authorizationSession.isAuthorizedNoLog(admin, "/super_administrator")) {
            String msg = intres.getLocalizedMessage("caadmin.notauthorizedtorenew", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_NOTAUTHORIZEDTORESOURCE, msg);
            throw new AuthorizationDeniedException(msg);
        }

        // Get CA info.
        CAData cadata = CAData.findByIdOrThrow(entityManager, Integer.valueOf(caid));
        CA ca = cadata.getCA();
        if (ca.getStatus() == SecConst.CA_OFFLINE) {
          String msg = intres.getLocalizedMessage("error.catokenoffline", cadata.getName());
          throw new CATokenOfflineException(msg);
        }
        ArrayList<ExtendedCAServiceInfo> infos = new ArrayList<ExtendedCAServiceInfo>();
        infos.add(info);
        activateAndPublishExternalCAServices(admin, infos, ca);
        // Update CA in database
        cadata.setCA(ca);
    }

    @Override
    public void renewCA(Admin admin, int caid, String keystorepass, boolean regenerateKeys) throws CADoesntExistsException, AuthorizationDeniedException,
            CertPathValidatorException, CATokenOfflineException, CATokenAuthenticationFailedException {
        if (log.isTraceEnabled()) {
            log.trace(">CAAdminSession, renewCA(), caid=" + caid);
        }
        Collection<Certificate> cachain = null;
        Certificate cacertificate = null;
        // check authorization
        try {
            if(!authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.REGULAR_RENEWCA)) {
                Authorizer.throwAuthorizationException(admin, AccessRulesConstants.REGULAR_RENEWCA, null);
            }
            if (!authorizedToCA(admin, caid)) {
                throw new AuthorizationDeniedException("Not authorized to CA");
            }
        } catch (AuthorizationDeniedException e) {
            String msg = intres.getLocalizedMessage("caadmin.notauthorizedtorenew", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_NOTAUTHORIZEDTORESOURCE, msg, e);
            throw new AuthorizationDeniedException(msg);
        }

        // Get CA info.
        CAData cadata = null;
        try {
          cadata = CAData.findByIdOrThrow(entityManager, Integer.valueOf(caid));
            CA ca = cadata.getCA();

            if (ca.getStatus() == SecConst.CA_OFFLINE) {
                String msg = intres.getLocalizedMessage("error.catokenoffline", cadata.getName());
                throw new CATokenOfflineException(msg);
            }

            CATokenContainer caToken = ca.getCAToken();
            if (regenerateKeys) {
                boolean renew = true;
                keystorepass = getDefaultKeyStorePassIfSWAndEmpty(keystorepass, caToken.getCATokenInfo());
                // for internal CAs the new keys are always activated
                caToken.generateKeys(keystorepass, renew, true);
                // We need to save all this
                ca.setCAToken(caToken);
                cadata.setCA(ca);
                // After this we need to reload all CAs?
                // Make sure we store the new CA and token and reload or update
                // the caches
                Provider prov = Security.getProvider(caToken.getProvider());
                if (log.isDebugEnabled() && (prov != null)) {
                    log.debug("Provider classname: " + prov.getClass().getName());
                }
                if ((prov != null) && StringUtils.contains(prov.getClass().getName(), "iaik")) {
                    // This is because IAIK PKCS#11 provider cuts ALL PKCS#11
                    // sessions when I generate new keys for one CA
                    CACacheManager.instance().removeAll();
                    CATokenManager.instance().removeAll();
                } else {
                    // Using the Sun provider we don't have to reload every CA,
                    // just update values in the caches
                    CACacheManager.instance().removeCA(ca.getCAId());
                    CATokenManager.instance().removeCAToken(ca.getCAId());
                }
              cadata = CAData.findByIdOrThrow(entityManager, Integer.valueOf(caid));
                ca = cadata.getCA();
                // In order to generate a certificate with this keystore we must
                // make sure it is activated
                caToken = ca.getCAToken();
                caToken.activate(keystorepass);
            }

            // if issuer is insystem CA or selfsigned, then generate new
            // certificate.
            if (ca.getSignedBy() != CAInfo.SIGNEDBYEXTERNALCA) {
                if (ca.getSignedBy() == CAInfo.SELFSIGNED) {
                    // create selfsigned certificate
                    String subjectAltName = null;
                    if (ca instanceof X509CA) {
                        X509CA x509ca = (X509CA) ca;
                        subjectAltName = x509ca.getSubjectAltName();
                    }
                    UserDataVO cainfodata = new UserDataVO("nobody", ca.getSubjectDN(), ca.getSubjectDN().hashCode(), subjectAltName, null, 0, 0, 0, ca
                            .getCertificateProfileId(), null, null, 0, 0, null);

                    CertificateProfile certprofile = certificateProfileSession.getCertificateProfile(admin, ca.getCertificateProfileId());
                    // get from CAtoken to make sure it is fresh
                    String sequence = caToken.getCATokenInfo().getKeySequence();
                    cacertificate = ca.generateCertificate(cainfodata, ca.getCAToken().getPublicKey(SecConst.CAKEYPURPOSE_CERTSIGN), -1, ca.getValidity(),
                            certprofile, sequence);
                    // Build Certificate Chain
                    cachain = new ArrayList<Certificate>();
                    cachain.add(cacertificate);

                } else {
                    // Resign with CA above.
                    if (ca.getSignedBy() > CAInfo.SPECIALCAIDBORDER || ca.getSignedBy() < 0) {
                        // Create CA signed by other internal CA.
                      CAData signcadata = CAData.findByIdOrThrow(entityManager, Integer.valueOf(ca.getSignedBy()));
                        CA signca = signcadata.getCA();
                        // Check that the signer is valid
                        checkSignerValidity(admin, signcadata);
                        // Create cacertificate
                        String subjectAltName = null;
                        if (ca instanceof X509CA) {
                            X509CA x509ca = (X509CA) ca;
                            subjectAltName = x509ca.getSubjectAltName();
                        }
                        UserDataVO cainfodata = new UserDataVO("nobody", ca.getSubjectDN(), ca.getSubjectDN().hashCode(), subjectAltName, null, 0, 0, 0, ca
                                .getCertificateProfileId(), null, null, 0, 0, null);

                        CertificateProfile certprofile = certificateProfileSession.getCertificateProfile(admin, ca.getCertificateProfileId());
                        String sequence = caToken.getCATokenInfo().getKeySequence(); // get from CAtoken to make sure it is fresh
                        cacertificate = signca.generateCertificate(cainfodata, ca.getCAToken().getPublicKey(SecConst.CAKEYPURPOSE_CERTSIGN), -1, ca
                                .getValidity(), certprofile, sequence);
                        // Build Certificate Chain
                        Collection<Certificate> rootcachain = signca.getCertificateChain();
                        cachain = new ArrayList<Certificate>();
                        cachain.add(cacertificate);
                        cachain.addAll(rootcachain);
                    }
                }
            } else {
                // We should never get here
                log.error("Directly renewing a CA signed by external can not be done");
                throw new NotSupportedException("Directly renewing a CA signed by external can not be done");
            }
            // Set statuses and expire time
            cadata.setExpireTime(CertTools.getNotAfter(cacertificate).getTime());
            ca.setExpireTime(CertTools.getNotAfter(cacertificate));
            cadata.setStatus(SecConst.CA_ACTIVE);
            ca.setStatus(SecConst.CA_ACTIVE);

            ca.setCertificateChain(cachain);
            cadata.setCA(ca);

            // Publish the new CA certificate
            publishCACertificate(admin, cachain, ca.getCRLPublishers(), ca.getSubjectDN());
            crlCreateSession.createCRLs(admin, ca, ca.getCAInfo());
        } catch (CATokenOfflineException e) {
            String msg = intres.getLocalizedMessage("caadmin.errorrenewca", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
            throw e;
        } catch (CATokenAuthenticationFailedException e) {
            String msg = intres.getLocalizedMessage("caadmin.errorrenewca", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
            throw e;
        } catch (Exception e) {
            String msg = intres.getLocalizedMessage("caadmin.errorrenewca", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
            throw new EJBException(e);
        }
        String msg = intres.getLocalizedMessage("caadmin.renewdca", Integer.valueOf(caid));
        logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CARENEWED, msg);
        if (log.isTraceEnabled()) {
            log.trace("<CAAdminSession, renewCA(), caid=" + caid);
        }
    }

    /**
     * Soft KeyStores can not have empty passwords, it probably means to use the
     * default one
     *
     * @param keystorepass The password that can not be empty if SW.
     * @param tokenInfo Used to determine if it is a soft token
     * @return The password to use.
     */
    private String getDefaultKeyStorePassIfSWAndEmpty(final String keystorepass, CATokenInfo tokenInfo) {
        if (tokenInfo instanceof SoftCATokenInfo && StringUtils.isEmpty(keystorepass)) {
            log.debug("Using system default keystore password");
            final String newKeystorepass = EjbcaConfiguration.getCaKeyStorePass();
            return StringTools.passwordDecryption(newKeystorepass, "ca.keystorepass");
        }
        return keystorepass;
    }

    @Override
    public void revokeCA(Admin admin, int caid, int reason) throws CADoesntExistsException, AuthorizationDeniedException {
        // check authorization
        if(!authorizationSession.isAuthorizedNoLog(admin, "/super_administrator")) {
            String msg = intres.getLocalizedMessage("caadmin.notauthorizedtorevoke", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_NOTAUTHORIZEDTORESOURCE, msg);
            throw new AuthorizationDeniedException(msg);
        }
        // Get CA info.
        CAData cadata = CAData.findByIdOrThrow(entityManager, Integer.valueOf(caid));
        String issuerdn = cadata.getSubjectDN();
        try {
            CA ca = cadata.getCA();
            // Revoke CA certificate
            certificateStoreSession.revokeCertificate(admin, ca.getCACertificate(), ca.getCRLPublishers(), reason, cadata.getSubjectDN());
            // Revoke all certificates generated by CA
            if (ca.getStatus() != SecConst.CA_EXTERNAL) {
                certificateStoreSession.revokeAllCertByCA(admin, issuerdn, RevokedCertInfo.REVOCATION_REASON_CACOMPROMISE);
                crlCreateSession.run(admin, ca);
            }
            ca.setRevocationReason(reason);
            ca.setRevocationDate(new Date());
            if (ca.getStatus() != SecConst.CA_EXTERNAL) {
                ca.setStatus(SecConst.CA_REVOKED);
            }
            cadata.setCA(ca);
        } catch (Exception e) {
            String msg = intres.getLocalizedMessage("caadmin.errorrevoke", cadata.getName());
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAREVOKED, msg, e);
            throw new EJBException(e);
        }
        String msg = intres.getLocalizedMessage("caadmin.revokedca", cadata.getName(), Integer.valueOf(reason));
        logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CAREVOKED, msg);
    }

    @Override
    public void importCAFromKeyStore(Admin admin, String caname, byte[] p12file, String keystorepass, String privkeypass, String privateSignatureKeyAlias,
            String privateEncryptionKeyAlias) throws Exception {
        try {
            // check authorization
            if (admin.getAdminType() != Admin.TYPE_CACOMMANDLINE_USER && !authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.ROLE_SUPERADMINISTRATOR)) {
                Authorizer.throwAuthorizationException(admin, AccessRulesConstants.ROLE_SUPERADMINISTRATOR, null);
            }
            // load keystore
            java.security.KeyStore keystore = KeyStore.getInstance("PKCS12", "BC");
            keystore.load(new java.io.ByteArrayInputStream(p12file), keystorepass.toCharArray());
            // Extract signature keys
            if (privateSignatureKeyAlias == null || !keystore.isKeyEntry(privateSignatureKeyAlias)) {
                throw new Exception("Alias \"" + privateSignatureKeyAlias + "\" not found.");
            }
            Certificate[] signatureCertChain = KeyTools.getCertChain(keystore, privateSignatureKeyAlias);
            if (signatureCertChain.length < 1) {
                String msg = "Cannot load certificate chain with alias " + privateSignatureKeyAlias;
                log.error(msg);
                throw new Exception(msg);
            }
            Certificate caSignatureCertificate = (Certificate) signatureCertChain[0];
            PublicKey p12PublicSignatureKey = caSignatureCertificate.getPublicKey();
            PrivateKey p12PrivateSignatureKey = null;
            p12PrivateSignatureKey = (PrivateKey) keystore.getKey(privateSignatureKeyAlias, privkeypass.toCharArray());
            log.debug("ImportSignatureKeyAlgorithm=" + p12PrivateSignatureKey.getAlgorithm());

            // Extract encryption keys
            PrivateKey p12PrivateEncryptionKey = null;
            PublicKey p12PublicEncryptionKey = null;
            Certificate caEncryptionCertificate = null;
            if (privateEncryptionKeyAlias != null) {
                if (!keystore.isKeyEntry(privateEncryptionKeyAlias)) {
                    throw new Exception("Alias \"" + privateEncryptionKeyAlias + "\" not found.");
                }
                Certificate[] encryptionCertChain = KeyTools.getCertChain(keystore, privateEncryptionKeyAlias);
                if (encryptionCertChain.length < 1) {
                    String msg = "Cannot load certificate chain with alias " + privateEncryptionKeyAlias;
                    log.error(msg);
                    throw new Exception(msg);
                }
                caEncryptionCertificate = (Certificate) encryptionCertChain[0];
                p12PrivateEncryptionKey = (PrivateKey) keystore.getKey(privateEncryptionKeyAlias, privkeypass.toCharArray());
                p12PublicEncryptionKey = caEncryptionCertificate.getPublicKey();
            }
            importCAFromKeys(admin, caname, keystorepass, signatureCertChain, p12PublicSignatureKey, p12PrivateSignatureKey, p12PrivateEncryptionKey,
                    p12PublicEncryptionKey);
        } catch (Exception e) {
            String msg = intres.getLocalizedMessage("caadmin.errorimportca", caname, "PKCS12", e.getMessage());
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg, e);
            throw new EJBException(e);
        }
    }

    @Override
    public void removeCAKeyStore(Admin admin, String caname) throws EJBException {
        try {
            // check authorization
            if (admin.getAdminType() != Admin.TYPE_CACOMMANDLINE_USER) {
                if(!authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.ROLE_SUPERADMINISTRATOR)) {
                    Authorizer.throwAuthorizationException(admin, AccessRulesConstants.ROLE_SUPERADMINISTRATOR, null);
                }
            }
            CAData caData = CAData.findByNameOrThrow(entityManager, caname);
            CA thisCa = caData.getCA();
            CATokenContainer thisCAToken = thisCa.getCAToken();
            int tokentype = thisCAToken.getCATokenType();
            if (tokentype != CATokenConstants.CATOKENTYPE_P12 && thisCAToken.getCATokenInfo() instanceof SoftCATokenInfo) {
                throw new Exception("Cannot export anything but a soft token.");
            }
            // Create a new CAToken with the same properties but OFFLINE and
            // without keystore
            SoftCATokenInfo thisCATokenInfo = (SoftCATokenInfo) thisCAToken.getCATokenInfo();
            thisCATokenInfo.setCATokenStatus(ICAToken.STATUS_OFFLINE);
            CATokenContainer emptyToken = new CATokenContainerImpl(thisCATokenInfo, caData.getCaId());
            thisCa.setCAToken(emptyToken);
            // Save to database
            caData.setCA(thisCa);
            // Log
            String msg = intres.getLocalizedMessage("caadmin.removedcakeystore", Integer.valueOf(thisCa.getCAId()));
            logSession.log(admin, thisCa.getCAId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CAEDITED, msg);
        } catch (Exception e) {
            String msg = intres.getLocalizedMessage("caadmin.errorremovecakeystore", caname, "PKCS12", e.getMessage());
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg, e);
            throw new EJBException(e);
        }
    }

    @Override
    public void restoreCAKeyStore(Admin admin, String caname, byte[] p12file, String keystorepass, String privkeypass, String privateSignatureKeyAlias,
            String privateEncryptionKeyAlias) throws EJBException {
        try {
            // check authorization
            if (admin.getAdminType() != Admin.TYPE_CACOMMANDLINE_USER) {
                if (!authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.ROLE_SUPERADMINISTRATOR)) {
                    Authorizer.throwAuthorizationException(admin, AccessRulesConstants.ROLE_SUPERADMINISTRATOR, null);
                }
            }

            CAData caData = CAData.findByNameOrThrow(entityManager, caname);
            CA thisCa = caData.getCA();

            CATokenContainer thisCAToken = thisCa.getCAToken();
            int tokentype = thisCAToken.getCATokenType();
            if (tokentype != CATokenConstants.CATOKENTYPE_P12 && thisCAToken.getCATokenInfo() instanceof SoftCATokenInfo) {
                throw new Exception("Cannot restore anything but a soft token.");
            }

            // Only restore to an offline CA
            if (thisCAToken.getCATokenInfo().getCATokenStatus() != ICAToken.STATUS_OFFLINE) {
                throw new Exception("The CA already has an active CA token.");
            }

            // load keystore
            KeyStore keystore = KeyStore.getInstance("PKCS12", "BC");
            keystore.load(new ByteArrayInputStream(p12file), keystorepass.toCharArray());
            // Extract signature keys
            if (privateSignatureKeyAlias == null || !keystore.isKeyEntry(privateSignatureKeyAlias)) {
                throw new Exception("Alias \"" + privateSignatureKeyAlias + "\" not found.");
            }
            Certificate[] signatureCertChain = KeyTools.getCertChain(keystore, privateSignatureKeyAlias);
            if (signatureCertChain.length < 1) {
                String msg = "Cannot load certificate chain with alias " + privateSignatureKeyAlias;
                log.error(msg);
                throw new Exception(msg);
            }
            Certificate caSignatureCertificate = (Certificate) signatureCertChain[0];
            PublicKey p12PublicSignatureKey = caSignatureCertificate.getPublicKey();
            PrivateKey p12PrivateSignatureKey = null;
            p12PrivateSignatureKey = (PrivateKey) keystore.getKey(privateSignatureKeyAlias, privkeypass.toCharArray());

            // Extract encryption keys
            PrivateKey p12PrivateEncryptionKey = null;
            PublicKey p12PublicEncryptionKey = null;
            Certificate caEncryptionCertificate = null;
            if (privateEncryptionKeyAlias != null) {
                if (!keystore.isKeyEntry(privateEncryptionKeyAlias)) {
                    throw new Exception("Alias \"" + privateEncryptionKeyAlias + "\" not found.");
                }
                Certificate[] encryptionCertChain = KeyTools.getCertChain(keystore, privateEncryptionKeyAlias);
                if (encryptionCertChain.length < 1) {
                    String msg = "Cannot load certificate chain with alias " + privateEncryptionKeyAlias;
                    log.error(msg);
                    throw new Exception(msg);
                }
                caEncryptionCertificate = (Certificate) encryptionCertChain[0];
                p12PrivateEncryptionKey = (PrivateKey) keystore.getKey(privateEncryptionKeyAlias, privkeypass.toCharArray());
                p12PublicEncryptionKey = caEncryptionCertificate.getPublicKey();
            } else {
                throw new Exception("Missing encryption key");
            }

            // Sign something to see that we are restoring the right private
            // signature key
            String testSigAlg = (String) AlgorithmTools.getSignatureAlgorithms(thisCa.getCACertificate().getPublicKey()).iterator().next();
            if (testSigAlg == null) {
                testSigAlg = "SHA1WithRSA";
            }
            // Sign with imported private key
            byte[] input = "Test data...".getBytes();
            Signature signature = Signature.getInstance(testSigAlg, "BC");
            signature.initSign(p12PrivateSignatureKey);
            signature.update(input);
            byte[] signed = signature.sign();
            // Verify with public key from CA certificate
            signature = Signature.getInstance(testSigAlg, "BC");
            signature.initVerify(thisCa.getCACertificate().getPublicKey());
            signature.update(input);
            if (!signature.verify(signed)) {
                throw new Exception("Could not use private key for verification. Wrong p12-file for this CA?");
            }

            // Import the keys and save to database
            thisCAToken.importKeys(keystorepass, p12PrivateSignatureKey, p12PublicSignatureKey, p12PrivateEncryptionKey, p12PublicEncryptionKey,
                    signatureCertChain);
            thisCa.setCAToken(thisCAToken);
            caData.setCA(thisCa);

            // Log
            String msg = intres.getLocalizedMessage("caadmin.restoredcakeystore", Integer.valueOf(thisCa.getCAId()));
            logSession.log(admin, thisCa.getCAId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CAEDITED, msg);
        } catch (Exception e) {
            String msg = intres.getLocalizedMessage("caadmin.errorrestorecakeystore", caname, "PKCS12", e.getMessage());
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg, e);
            throw new EJBException(e);
        }
    }

    @Override
    public void importCAFromKeys(Admin admin, String caname, String keystorepass, Certificate[] signatureCertChain, PublicKey p12PublicSignatureKey,
            PrivateKey p12PrivateSignatureKey, PrivateKey p12PrivateEncryptionKey, PublicKey p12PublicEncryptionKey) throws Exception,
            CATokenAuthenticationFailedException, CATokenOfflineException, IllegalKeyStoreException, CreateException {
        // Transform into token
        SoftCATokenInfo sinfo = new SoftCATokenInfo();
        CATokenContainer catoken = new CATokenContainerImpl(sinfo, CertTools.stringToBCDNString(
                StringTools.strip(CertTools.getSubjectDN(signatureCertChain[0]))).hashCode());
        catoken.importKeys(keystorepass, p12PrivateSignatureKey, p12PublicSignatureKey, p12PrivateEncryptionKey, p12PublicEncryptionKey, signatureCertChain);
        log.debug("CA-Info: " + catoken.getCATokenInfo().getSignatureAlgorithm() + " " + catoken.getCATokenInfo().getEncryptionAlgorithm());
        // Identify the key algorithms for extended CA services, OCSP, XKMS, CMS
        String keyAlgorithm = AlgorithmTools.getKeyAlgorithm(p12PublicSignatureKey);
        String keySpecification = AlgorithmTools.getKeySpecification(p12PublicSignatureKey);
        if (keyAlgorithm == null || keyAlgorithm == AlgorithmConstants.KEYALGORITHM_RSA) {
            keyAlgorithm = AlgorithmConstants.KEYALGORITHM_RSA;
            keySpecification = "2048";
        }
        // Do the general import
        CA ca = importCA(admin, caname, keystorepass, signatureCertChain, catoken, keyAlgorithm, keySpecification);
        String msg = intres.getLocalizedMessage("caadmin.importedca", caname, "PKCS12", ca.getStatus());
        logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CACREATED, msg);
    }

    @Override
    public void importCAFromHSM(Admin admin, String caname, Certificate[] signatureCertChain, String catokenpassword, String catokenclasspath,
            String catokenproperties) throws Exception {
        String signatureAlgorithm = CertTools.getSignatureAlgorithm((Certificate) signatureCertChain[0]);
        HardCATokenInfo hardcatokeninfo = new HardCATokenInfo();
        hardcatokeninfo.setAuthenticationCode(catokenpassword);
        hardcatokeninfo.setCATokenStatus(ICAToken.STATUS_ACTIVE);
        hardcatokeninfo.setClassPath(catokenclasspath);
        hardcatokeninfo.setEncryptionAlgorithm(AlgorithmConstants.SIGALG_SHA1_WITH_RSA);
        hardcatokeninfo.setProperties(catokenproperties);
        hardcatokeninfo.setSignatureAlgorithm(signatureAlgorithm);

        CATokenInfo catokeninfo = hardcatokeninfo;
        CATokenContainer catoken = new CATokenContainerImpl(catokeninfo, CertTools.stringToBCDNString(
                StringTools.strip(CertTools.getSubjectDN(signatureCertChain[0]))).hashCode());
        catoken.activate(catokenpassword);

        String keyAlgorithm = AlgorithmConstants.KEYALGORITHM_RSA;
        String keySpecification = "2048";
        // Do the general import
        importCA(admin, caname, catokenpassword, signatureCertChain, catoken, keyAlgorithm, keySpecification);
    }

    /**
     * @param keyAlgorithm
     *            keyalgorithm for extended CA services, OCSP, XKMS, CMS.
     *            Example AlgorithmConstants.KEYALGORITHM_RSA
     * @param keySpecification
     *            keyspecification for extended CA services, OCSP, XKMS, CMS.
     *            Example 2048
     */
    private CA importCA(Admin admin, String caname, String keystorepass, Certificate[] signatureCertChain, CATokenContainer catoken, String keyAlgorithm,
            String keySpecification) throws Exception, CATokenAuthenticationFailedException, CATokenOfflineException, IllegalKeyStoreException, CreateException {
        // Create a new CA
        int signedby = CAInfo.SIGNEDBYEXTERNALCA;
        int certprof = SecConst.CERTPROFILE_FIXED_SUBCA;
        String description = "Imported external signed CA";
        Certificate caSignatureCertificate = signatureCertChain[0];
        ArrayList<Certificate> certificatechain = new ArrayList<Certificate>();
        for (int i = 0; i < signatureCertChain.length; i++) {
            certificatechain.add(signatureCertChain[i]);
        }
        if (signatureCertChain.length == 1) {
            if (verifyIssuer(caSignatureCertificate, caSignatureCertificate)) {
                signedby = CAInfo.SELFSIGNED;
                certprof = SecConst.CERTPROFILE_FIXED_ROOTCA;
                description = "Imported root CA";
            } else {
                // A less strict strategy can be to assume certificate signed
                // by an external CA. Useful if admin user forgot to create a
                // full
                // certificate chain in PKCS#12 package.
                log.error("Cannot import CA " + CertTools.getSubjectDN(caSignatureCertificate) + ": certificate "
                        + CertTools.getSerialNumberAsString(caSignatureCertificate) + " is not self-signed.");
                throw new Exception("Cannot import CA " + CertTools.getSubjectDN(caSignatureCertificate) + ": certificate is not self-signed. Check "
                        + "certificate chain in PKCS#12");
            }
        } else if (signatureCertChain.length > 1) {
            Collection<Integer> cas = caSession.getAvailableCAs();
            Iterator<Integer> iter = cas.iterator();
            // Assuming certificate chain in forward direction (from target
            // to most-trusted CA). Multiple CA chains can contains the
            // issuer certificate; so only the chain where target certificate
            // is the issuer will be selected.
            while (iter.hasNext()) {
                int caid = iter.next().intValue();
                CAInfo superCaInfo = getCAInfo(admin, caid);
                Iterator<Certificate> i = superCaInfo.getCertificateChain().iterator();
                if (i.hasNext()) {
                    Certificate superCaCert = i.next();
                    if (verifyIssuer(caSignatureCertificate, superCaCert)) {
                        signedby = caid;
                        description = "Imported sub CA";
                        break;
                    }
                }
            }
        }

        CAInfo cainfo = null;
        CA ca = null;
        int validity = (int) ((CertTools.getNotAfter(caSignatureCertificate).getTime() - CertTools.getNotBefore(caSignatureCertificate).getTime()) / (24 * 3600 * 1000));
        ArrayList<ExtendedCAServiceInfo> extendedcaservices = new ArrayList<ExtendedCAServiceInfo>();
        ArrayList<Integer> approvalsettings = new ArrayList<Integer>();
        ArrayList<Integer> crlpublishers = new ArrayList<Integer>();
        if (caSignatureCertificate instanceof X509Certificate) {
            // Create an X509CA
            // Create and active extended CA Services (OCSP, XKMS, CMS).
            extendedcaservices.add(new OCSPCAServiceInfo(ExtendedCAServiceInfo.STATUS_ACTIVE));
            // Create and active XKMS CA Service.
            extendedcaservices.add(new XKMSCAServiceInfo(ExtendedCAServiceInfo.STATUS_INACTIVE, "CN=XKMSCertificate, "
                    + CertTools.getSubjectDN(caSignatureCertificate), "", keySpecification, keyAlgorithm));
            // Create and active CMS CA Service.
            extendedcaservices.add(new CmsCAServiceInfo(ExtendedCAServiceInfo.STATUS_INACTIVE, "CN=CMSCertificate, "
                    + CertTools.getSubjectDN(caSignatureCertificate), "", keySpecification, keyAlgorithm));

            cainfo = new X509CAInfo(CertTools.getSubjectDN(caSignatureCertificate), caname, SecConst.CA_ACTIVE, new Date(), "", certprof, validity, CertTools
                    .getNotAfter(caSignatureCertificate), // Expiretime
                    CAInfo.CATYPE_X509, signedby, certificatechain, catoken.getCATokenInfo(), description,
                    -1, // revocationReason
                    null, // revocationDate
                    null, // PolicyId
                    24 * SimpleTime.MILLISECONDS_PER_HOUR, // CRLPeriod
                    0 * SimpleTime.MILLISECONDS_PER_HOUR, // CRLIssuePeriod
                    10 * SimpleTime.MILLISECONDS_PER_HOUR, // CRLOverlapTime
                    0 * SimpleTime.MILLISECONDS_PER_HOUR, // DeltaCRLPeriod
                    crlpublishers, // CRL publishers
                    true, // Authority Key Identifier
                    false, // Authority Key Identifier Critical
                    true, // CRL Number
                    false, // CRL Number Critical
                    "", // Default CRL Dist Point
                    "", // Default CRL Issuer
                    "", // Default OCSP Service Locator
                    "", // CA defined freshest CRL
                    true, // Finish User
                    extendedcaservices, false, // use default utf8 settings
                    approvalsettings, // Approvals Settings
                    1, // Number of Req approvals
                    false, // Use UTF8 subject DN by default
                    true, // Use LDAP DN order by default
                    false, // Use CRL Distribution Point on CRL
                    false, // CRL Distribution Point on CRL critical,
                    true, // Include in HealthCheck
                    true, // isDoEnforceUniquePublicKeys
                    true, // isDoEnforceUniqueDistinguishedName
                    false, // isDoEnforceUniqueSubjectDNSerialnumber
                    true, // useCertReqHistory
                    true, // useUserStorage
                    true, // useCertificateStorage
                    null //cmpRaAuthSecret
            );
            ca = new X509CA((X509CAInfo) cainfo);
        } else if (caSignatureCertificate.getType().equals("CVC")) {
            // Create a CVC CA
            // Create the CAInfo to be used for either generating the whole CA
            // or making a request
            cainfo = new CVCCAInfo(CertTools.getSubjectDN(caSignatureCertificate), caname, SecConst.CA_ACTIVE, new Date(), certprof, validity, CertTools
                    .getNotAfter(caSignatureCertificate), CAInfo.CATYPE_CVC, signedby, certificatechain, catoken.getCATokenInfo(), description, -1,
                    (Date) null, 24, 0, 10, 0, // CRL periods
                    crlpublishers, // CRL publishers
                    true, // Finish user
                    extendedcaservices, approvalsettings, // Approvals Settings
                    1, // Number of Req approvals
                    true, // Include in HealthCheck
                    true, // isDoEnforceUniquePublicKeys
                    true, // isDoEnforceUniqueDistinguishedName
                    false, // isDoEnforceUniqueSubjectDNSerialnumber
                    true, // useCertReqHistory
                    true, // useUserStorage
                    true // useCertificateStorage
            );
            ca = new CVCCA((CVCCAInfo) cainfo);
        }
        // We must activate the token, in case it does not have the default
        // password
        catoken.activate(keystorepass);
        ca.setCAToken(catoken);
        ca.setCertificateChain(certificatechain);
        log.debug("CA-Info: " + catoken.getCATokenInfo().getSignatureAlgorithm() + " " + ca.getCAToken().getCATokenInfo().getEncryptionAlgorithm());
        // Publish CA certificates.
        publishCACertificate(admin, ca.getCertificateChain(), ca.getCRLPublishers(), ca.getSubjectDN());
        // activate External CA Services
        activateAndPublishExternalCAServices(admin, cainfo.getExtendedCAServiceInfos(), ca);
        // Store CA in database.
        entityManager.persist(new CAData(cainfo.getSubjectDN(), cainfo.getName(), SecConst.CA_ACTIVE, ca));
        crlCreateSession.run(admin, ca);
        return ca;
    }

    @Override
    public byte[] exportCAKeyStore(Admin admin, String caname, String keystorepass, String privkeypass, String privateSignatureKeyAlias,
            String privateEncryptionKeyAlias) throws Exception {
        log.trace(">exportCAKeyStore");
        try {
          CAData cadata = CAData.findByNameOrThrow(entityManager, caname);
          CA thisCa = cadata.getCA();
            // Make sure we are not trying to export a hard or invalid token
            CATokenContainer thisCAToken = thisCa.getCAToken();
            int tokentype = thisCAToken.getCATokenType();
            if (tokentype != CATokenConstants.CATOKENTYPE_P12) {
                throw new Exception("Cannot export anything but a soft token.");
            }
            // Check authorization
            if (admin.getAdminType() != Admin.TYPE_CACOMMANDLINE_USER && !authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.ROLE_SUPERADMINISTRATOR)) {
                Authorizer.throwAuthorizationException(admin, AccessRulesConstants.ROLE_SUPERADMINISTRATOR, null);
            }
            // Fetch keys
            // This is a way of verifying the password. If activate fails, we
            // will get an exception and the export will not proceed
            thisCAToken.activate(keystorepass);

            PrivateKey p12PrivateEncryptionKey = thisCAToken.getPrivateKey(SecConst.CAKEYPURPOSE_KEYENCRYPT);
            PublicKey p12PublicEncryptionKey = thisCAToken.getPublicKey(SecConst.CAKEYPURPOSE_KEYENCRYPT);
            PrivateKey p12PrivateCertSignKey = thisCAToken.getPrivateKey(SecConst.CAKEYPURPOSE_CERTSIGN);
            PrivateKey p12PrivateCRLSignKey = thisCAToken.getPrivateKey(SecConst.CAKEYPURPOSE_CRLSIGN);
            if (!p12PrivateCertSignKey.equals(p12PrivateCRLSignKey)) {
                throw new Exception("Assertion of equal signature keys failed.");
            }
            // Proceed with the export
            byte[] ret = null;
            String format = null;
            if (thisCa.getCAType() == CAInfo.CATYPE_CVC) {
                log.debug("Exporting private key with algorithm: " + p12PrivateCertSignKey.getAlgorithm() + " of format: " + p12PrivateCertSignKey.getFormat());
                format = p12PrivateCertSignKey.getFormat();
                ret = p12PrivateCertSignKey.getEncoded();
            } else {
                log.debug("Exporting PKCS12 keystore");
                format = "PKCS12";
                KeyStore keystore = KeyStore.getInstance("PKCS12", "BC");
                keystore.load(null, keystorepass.toCharArray());
                // Load keys into keystore
                Certificate[] certificateChainSignature = (Certificate[]) thisCa.getCertificateChain().toArray(new Certificate[0]);
                Certificate[] certificateChainEncryption = new Certificate[1];
                // certificateChainSignature[0].getSigAlgName(),
                // generate dummy certificate for encryption key.
                certificateChainEncryption[0] = CertTools.genSelfCertForPurpose("CN=dummy2", 36500, null, p12PrivateEncryptionKey, p12PublicEncryptionKey,
                        thisCAToken.getCATokenInfo().getEncryptionAlgorithm(), true, X509KeyUsage.keyEncipherment);
                log.debug("Exporting with sigAlgorithm " + CertTools.getSignatureAlgorithm(certificateChainSignature[0]) + "encAlgorithm="
                        + thisCAToken.getCATokenInfo().getEncryptionAlgorithm());
                if (keystore.isKeyEntry(privateSignatureKeyAlias)) {
                    throw new Exception("Key \"" + privateSignatureKeyAlias + "\"already exists in keystore.");
                }
                if (keystore.isKeyEntry(privateEncryptionKeyAlias)) {
                    throw new Exception("Key \"" + privateEncryptionKeyAlias + "\"already exists in keystore.");
                }

                keystore.setKeyEntry(privateSignatureKeyAlias, p12PrivateCertSignKey, privkeypass.toCharArray(), certificateChainSignature);
                keystore.setKeyEntry(privateEncryptionKeyAlias, p12PrivateEncryptionKey, privkeypass.toCharArray(), certificateChainEncryption);
                // Return KeyStore as byte array and clean up
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                keystore.store(baos, keystorepass.toCharArray());
                if (keystore.isKeyEntry(privateSignatureKeyAlias)) {
                    keystore.deleteEntry(privateSignatureKeyAlias);
                }
                if (keystore.isKeyEntry(privateEncryptionKeyAlias)) {
                    keystore.deleteEntry(privateEncryptionKeyAlias);
                }
                ret = baos.toByteArray();
            }
            String msg = intres.getLocalizedMessage("caadmin.exportedca", caname, format);
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CAEXPORTED, msg);
            log.trace("<exportCAKeyStore");
            return ret;
        } catch (Exception e) {
            String msg = intres.getLocalizedMessage("caadmin.errorexportca", caname, "PKCS12", e.getMessage());
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEXPORTED, msg, e);
            throw new EJBException(e);
        }
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    @Override
    public Collection<Certificate> getAllCACertificates() {
        ArrayList<Certificate> returnval = new ArrayList<Certificate>();

        try {
            Collection<Integer> caids = caSession.getAvailableCAs();
            Iterator<Integer> iter = caids.iterator();
            while (iter.hasNext()) {
                Integer caid = iter.next();
                CAData cadata = CAData.findById(entityManager, Integer.valueOf(caid));
                if (cadata == null) {
                  log.error("Can't find CA: " + caid);
                }
                CA ca = cadata.getCA();
                if (log.isDebugEnabled()) {
                    log.debug("Getting certificate chain for CA: " + ca.getName() + ", " + ca.getCAId());
                }
                returnval.add(ca.getCACertificate());
            }
        } catch (UnsupportedEncodingException uee) {
            throw new EJBException(uee);
        } catch (IllegalKeyStoreException e) {
            throw new EJBException(e);
        }
        return returnval;
    }

    //FIXME: Fix exception handling for this method.
    @Override
    public String getKeyFingerPrint(Admin admin, String caname) throws Exception {
            if (admin.getAdminType() != Admin.TYPE_CACOMMANDLINE_USER) {
                if(!authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.ROLE_SUPERADMINISTRATOR)) {
                    Authorizer.throwAuthorizationException(admin, AccessRulesConstants.ROLE_SUPERADMINISTRATOR, null);
                }
            }
          CAData cadata = CAData.findByNameOrThrow(entityManager, caname);
          CA thisCa = cadata.getCA();

            // Make sure we are not trying to export a hard or invalid token
            if (thisCa.getCAType() != CATokenConstants.CATOKENTYPE_P12) {
                throw new Exception("Cannot extract fingerprint from a non-soft token (" + thisCa.getCAType() + ").");
            }
            // Fetch keys
            CATokenContainer thisCAToken = thisCa.getCAToken();
            PrivateKey p12PrivateEncryptionKey = thisCAToken.getPrivateKey(SecConst.CAKEYPURPOSE_KEYENCRYPT);
            PrivateKey p12PrivateCertSignKey = thisCAToken.getPrivateKey(SecConst.CAKEYPURPOSE_CERTSIGN);
            PrivateKey p12PrivateCRLSignKey = thisCAToken.getPrivateKey(SecConst.CAKEYPURPOSE_CRLSIGN);
            MessageDigest md = MessageDigest.getInstance("SHA1");
            md.update(p12PrivateEncryptionKey.getEncoded());
            md.update(p12PrivateCertSignKey.getEncoded());
            md.update(p12PrivateCRLSignKey.getEncoded());
            return new String(Hex.encode(md.digest()));
    }

    @Override
    public void activateCAToken(Admin admin, int caid, String authorizationcode, GlobalConfiguration gc) throws AuthorizationDeniedException,
            CATokenAuthenticationFailedException, CATokenOfflineException, ApprovalException, WaitingForApprovalException {
        // Authorize
        if(!authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.REGULAR_ACTIVATECA)) {
            String msg = intres.getLocalizedMessage("caadmin.notauthorizedtoactivatetoken", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_NOTAUTHORIZEDTORESOURCE, msg);
            throw new AuthorizationDeniedException(msg);
        }

        // Check if approvals is required.
        CAInfo cainfo = getCAInfo(admin, caid);
        if (cainfo == null) {
            String msg = intres.getLocalizedMessage("caadmin.errorgetcainfo", Integer.valueOf(caid));
            log.error(msg);
            return;
        }
        if (cainfo.getStatus() == SecConst.CA_EXTERNAL) {
            String msg = intres.getLocalizedMessage("caadmin.catokenexternal", Integer.valueOf(caid));
            log.info(msg);
            return;
        }
        int numOfApprovalsRequired = getNumOfApprovalRequired(admin, CAInfo.REQ_APPROVAL_ACTIVATECATOKEN, cainfo.getCAId(), cainfo.getCertificateProfileId());
        ActivateCATokenApprovalRequest ar = new ActivateCATokenApprovalRequest(cainfo.getName(), authorizationcode, admin, numOfApprovalsRequired, caid,
                ApprovalDataVO.ANY_ENDENTITYPROFILE);
        if (ApprovalExecutorUtil.requireApproval(ar, NONAPPROVABLECLASSNAMES_ACTIVATECATOKEN)) {
            approvalSession.addApprovalRequest(admin, ar, gc);
            String msg = intres.getLocalizedMessage("ra.approvalcaactivation");
            throw new WaitingForApprovalException(msg);
        }
        if (caid >= 0 && caid <= CAInfo.SPECIALCAIDBORDER) {
          String msg = intres.getLocalizedMessage("caadmin.erroractivatetoken", Integer.valueOf(caid));
          logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg);
          throw new CATokenAuthenticationFailedException(msg);
        }
        CAData cadata = CAData.findById(entityManager, Integer.valueOf(caid));
        if (cadata == null) {
          String msg = intres.getLocalizedMessage("caadmin.errorcanotfound", Integer.valueOf(caid));
          logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg);
          throw new EJBException(msg);
        }
        boolean cATokenDisconnected = false;
        try {
          if ((cadata.getCA().getCAToken().getCATokenInfo()).getCATokenStatus() == ICAToken.STATUS_OFFLINE) {
            cATokenDisconnected = true;
          }
        } catch (IllegalKeyStoreException e) {
          String msg = intres.getLocalizedMessage("caadmin.errorreadingtoken", Integer.valueOf(caid));
          log.error(msg, e);
        } catch (UnsupportedEncodingException e) {
          String msg = intres.getLocalizedMessage("caadmin.errorreadingtoken", Integer.valueOf(caid));
          log.error(msg, e);
        }
        if (cadata.getStatus() == SecConst.CA_OFFLINE || cATokenDisconnected) {
          try {
            cadata.getCA().getCAToken().activate(authorizationcode);
            // If the CA was off-line, this is activation of the CA, if
            // only the token was disconnected we only connect the token
            // If CA is waiting for certificate response we can not
            // change this status just by activating the token.
            if (cadata.getStatus() != SecConst.CA_WAITING_CERTIFICATE_RESPONSE) {
              cadata.setStatus(SecConst.CA_ACTIVE);
            }
            // Invalidate CA cache to refresh information
            CACacheManager.instance().removeCA(cadata.getCaId().intValue());
            String msg = intres.getLocalizedMessage("caadmin.catokenactivated", cadata.getName());
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CAEDITED, msg);
          } catch (CATokenAuthenticationFailedException e) {
            String msg = intres.getLocalizedMessage("caadmin.badcaactivationcode", cadata.getName());
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAACTIVATIONCODE, msg);
            throw e;
          } catch (IllegalKeyStoreException e) {
            throw new EJBException(e);
          } catch (UnsupportedEncodingException e) {
            throw new EJBException(e);
          }
        } else {
          String msg = intres.getLocalizedMessage("caadmin.errornotoffline", cadata.getName());
          logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg);
          throw new CATokenAuthenticationFailedException(msg);
        }
    }

    private static final ApprovalOveradableClassName[] NONAPPROVABLECLASSNAMES_ACTIVATECATOKEN = { new ApprovalOveradableClassName(
            org.ejbca.core.model.approval.approvalrequests.ActivateCATokenApprovalRequest.class.getName(), null), };

    @Override
    public void deactivateCAToken(Admin admin, int caid) throws AuthorizationDeniedException, EjbcaException {
        // Authorize
        if(!authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.REGULAR_ACTIVATECA)) {
            String msg = intres.getLocalizedMessage("caadmin.notauthorizedtodeactivatetoken", Integer.valueOf(caid));
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_NOTAUTHORIZEDTORESOURCE, msg);
            throw new AuthorizationDeniedException(msg);
        }
        if (caid >= 0 && caid <= CAInfo.SPECIALCAIDBORDER) {
          // This should never happen.
          String msg = intres.getLocalizedMessage("caadmin.errordeactivatetoken", Integer.valueOf(caid));
          logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg);
          throw new EjbcaException(msg);
        }
        CAData cadata = CAData.findById(entityManager, Integer.valueOf(caid));
        if (cadata == null) {
          String msg = intres.getLocalizedMessage("caadmin.errorcanotfound", Integer.valueOf(caid));
          logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg);
          throw new EJBException(msg);
        }
        if (cadata.getStatus() == SecConst.CA_EXTERNAL) {
          String msg = intres.getLocalizedMessage("caadmin.catokenexternal", Integer.valueOf(caid));
          log.info(msg);
          return;
        } else if (cadata.getStatus() == SecConst.CA_ACTIVE) {
          try {
            cadata.getCA().getCAToken().deactivate();
            cadata.setStatus(SecConst.CA_OFFLINE);
            // Invalidate CA cache to refresh information
            CACacheManager.instance().removeCA(cadata.getCaId().intValue());
            String msg = intres.getLocalizedMessage("caadmin.catokendeactivated", cadata.getName());
            logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_CAEDITED, msg);
          } catch (Exception e) {
            throw new EJBException(e);
          }
        } else {
          String msg = intres.getLocalizedMessage("caadmin.errornotonline", cadata.getName());
          logSession.log(admin, caid, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED, msg);
          throw new EjbcaException(msg);
        }
    }

    /** Method used to check if certificate profile id exists in any CA. */
    @Override
    public boolean exitsCertificateProfileInCAs(Admin admin, int certificateprofileid) {
        boolean returnval = false;
        try {
          Collection<CAData> result = CAData.findAll(entityManager);
            Iterator<CAData> iter = result.iterator();
            while (iter.hasNext()) {
                CAData cadata = iter.next();
                returnval = returnval || (cadata.getCA().getCertificateProfileId() == certificateprofileid);
            }
        } catch (java.io.UnsupportedEncodingException e) {
        } catch (IllegalKeyStoreException e) {
        }
        return returnval;
    }

    @Override
    public byte[] encryptWithCA(int caid, byte[] data) throws Exception {
      CAData caData = CAData.findByIdOrThrow(entityManager, Integer.valueOf(caid));
        return caData.getCA().encryptData(data, SecConst.CAKEYPURPOSE_KEYENCRYPT);
    }

    @Override
    public byte[] decryptWithCA(int caid, byte[] data) throws Exception {
      CAData caData = CAData.findByIdOrThrow(entityManager, Integer.valueOf(caid));
        return caData.getCA().decryptData(data, SecConst.CAKEYPURPOSE_KEYENCRYPT);
    }

    @Override
    public boolean exitsPublisherInCAs(Admin admin, int publisherid) {
        boolean returnval = false;
        try {
          Collection<CAData> result = CAData.findAll(entityManager);
            Iterator<CAData> iter = result.iterator();
            while (iter.hasNext()) {
                CAData cadata = iter.next();
                Iterator<Integer> pubiter = cadata.getCA().getCRLPublishers().iterator();
                while (pubiter.hasNext()) {
                    Integer pubInt = pubiter.next();
                    returnval = returnval || (pubInt.intValue() == publisherid);
                }
            }
        } catch (java.io.UnsupportedEncodingException e) {
        } catch (IllegalKeyStoreException e) {
        }
        return returnval;
    }

    @Override
    public int getNumOfApprovalRequired(Admin admin, int action, int caid, int certProfileId) {
        int retval = 0;
        CAInfo cainfo = getCAInfo(admin, caid);
        if (cainfo != null) {
            if (cainfo.isApprovalRequired(action)) {
                retval = cainfo.getNumOfReqApprovals();
            }
            CertificateProfile certprofile = certificateProfileSession.getCertificateProfile(admin, certProfileId);
            if (certprofile != null && certprofile.isApprovalRequired(action)) {
                retval = Math.max(retval, certprofile.getNumOfReqApprovals());
            }
        }
        return retval;
    }

    @Override
    public void publishCACertificate(Admin admin, Collection<Certificate> certificatechain, Collection<Integer> usedpublishers, String caDataDN) {
        try {
            Object[] certs = certificatechain.toArray();
            for (int i = 0; i < certs.length; i++) {
                Certificate cert = (Certificate) certs[i];
                String fingerprint = CertTools.getFingerprintAsString(cert);
                // CA fingerprint, figure out the value if this is not a root CA
                String cafp = fingerprint;
                // Calculate the certificate type
                boolean isSelfSigned = CertTools.isSelfSigned(cert);
                int type = SecConst.CERTTYPE_ENDENTITY;
                if (CertTools.isCA(cert)) {
                    // this is a CA
                    if (isSelfSigned) {
                        type = SecConst.CERTTYPE_ROOTCA;
                    } else {
                        type = SecConst.CERTTYPE_SUBCA;
                        // If not a root CA, the next certificate in the chain
                        // should be the CA of this CA
                        if ((i + 1) < certs.length) {
                            Certificate cacert = (Certificate) certs[i + 1];
                            cafp = CertTools.getFingerprintAsString(cacert);
                        }
                    }
                } else if (isSelfSigned) {
                    // If we don't have basic constraints, but is self signed,
                    // we are still a CA, just a stupid CA
                    type = SecConst.CERTTYPE_ROOTCA;
                } else {
                    // If and end entity, the next certificate in the chain
                    // should be the CA of this end entity
                    if ((i + 1) < certs.length) {
                        Certificate cacert = (Certificate) certs[i + 1];
                        cafp = CertTools.getFingerprintAsString(cacert);
                    }
                }

                String name = "SYSTEMCERT";
                if (type != SecConst.CERTTYPE_ENDENTITY) {
                    name = "SYSTEMCA";
                }
                // Store CA certificate in the database if it does not exist
                long updateTime = new Date().getTime();
                int profileId = 0;
                String tag = null;
                CertificateInfo ci = certificateStoreSession.getCertificateInfo(admin, fingerprint);
                if (ci == null) {
                    // If we don't have it in the database, store it setting
                    // certificateProfileId = 0 and tag = null
                    certificateStoreSession.storeCertificate(admin, cert, name, cafp, SecConst.CERT_ACTIVE, type, profileId, tag, updateTime);
                } else {
                    updateTime = ci.getUpdateTime().getTime();
                    profileId = ci.getCertificateProfileId();
                    tag = ci.getTag();
                }
                if (usedpublishers != null) {
                    publisherSession.storeCertificate(admin, usedpublishers, cert, cafp, null, caDataDN, fingerprint, SecConst.CERT_ACTIVE, type, -1,
                            RevokedCertInfo.NOT_REVOKED, tag, profileId, updateTime, null);
                }
            }
        } catch (javax.ejb.CreateException ce) {
            throw new EJBException(ce);
        }
    }

    @Override
    public Collection<Integer> getAuthorizedPublisherIds(Admin admin) {
        HashSet<Integer> returnval = new HashSet<Integer>();
        try {
            // If superadmin return all available publishers
            returnval.addAll(publisherSession.getAllPublisherIds(admin));
        } catch (AuthorizationDeniedException e1) {
            // If regular CA-admin return publishers he is authorized to
            Iterator<Integer> authorizedcas = caSession.getAvailableCAs(admin).iterator();
            while (authorizedcas.hasNext()) {
                returnval.addAll(getCAInfo(admin, authorizedcas.next().intValue()).getCRLPublishers());
            }
        }
        return returnval;
    }

    private boolean authorizedToCA(Admin admin, int caid) {
        return authorizationSession.isAuthorizedNoLog(admin, AccessRulesConstants.CAPREFIX + caid);
    }

    @TransactionAttribute(TransactionAttributeType.SUPPORTS)
    @Override
    public String healthCheck() {
        String returnval = "";
        final Admin admin = Admin.getInternalAdmin();
        boolean caTokenSignTest = EjbcaConfiguration.getHealthCheckCaTokenSignTest();
        log.debug("CaTokenSignTest: " + caTokenSignTest);
        Iterator<Integer> iter = caSession.getAvailableCAs().iterator();
        while (iter.hasNext()) {
            int caid = iter.next().intValue();
            CAInfo cainfo = getCAInfo(admin, caid, caTokenSignTest);
            if ((cainfo.getStatus() == SecConst.CA_ACTIVE) && cainfo.getIncludeInHealthCheck()) {
                int tokenstatus = cainfo.getCATokenInfo().getCATokenStatus();
                if (tokenstatus == ICAToken.STATUS_OFFLINE) {
                    returnval += "\nCA: Error CA Token is disconnected, CA Name : " + cainfo.getName();
                    log.error("Error CA Token is disconnected, CA Name : " + cainfo.getName());
                }
            }
        }
        return returnval;
    }

    @Override
    public ExtendedCAServiceResponse extendedService(Admin admin, int caid, ExtendedCAServiceRequest request)
            throws ExtendedCAServiceRequestException, IllegalExtendedCAServiceRequestException, ExtendedCAServiceNotActiveException, CADoesntExistsException {
        // Get CA that will process request
        CA ca = caSession.getCA(admin, caid);
        if (log.isDebugEnabled()) {
          log.debug("Exteneded service with request class '"+request.getClass().getName()+"' called for CA '"+ca.getName()+"'");             
        }
        return ca.extendedService(request);
    }

    //
    // Private methods
    //

    /**
     * Check if subject certificate is signed by issuer certificate. Used in
     *
     * @see #upgradeFromOldCAKeyStore(Admin, String, byte[], char[], char[],
     *      String). This method does a lazy check: if signature verification
     *      failed for any reason that prevent verification, e.g. signature
     *      algorithm not supported, method returns false. Author: Marco
     *      Ferrante
     *
     * @param subject
     *            Subject certificate
     * @param issuer
     *            Issuer certificate
     * @return true if subject certificate is signed by issuer certificate
     * @throws java.lang.Exception
     */
    private boolean verifyIssuer(Certificate subject, Certificate issuer) throws Exception {
        try {
            PublicKey issuerKey = issuer.getPublicKey();
            subject.verify(issuerKey);
            return true;
        } catch (java.security.GeneralSecurityException e) {
            return false;
        }
    }

    /**
     * Checks the signer validity given a CADataLocal object, as a side-effect
     * marks the signer as expired if it is expired, and throws an EJBException
     * to the caller. This should only be called from create and edit CA methods.
     *
     * @param admin
     *            administrator calling the method
     * @param signcadata
     *            a CADataLocal entity object of the signer to be checked
     * @throws UnsupportedEncodingException
     *             if there is an error getting the CA from the CADataLoca
     * @throws IllegalKeyStoreException
     *             if we can not read the CA, with it's keystore
     * @throws EJBException
     *             embedding a CertificateExpiredException or a
     *             CertificateNotYetValidException if the certificate has
     *             expired or is not yet valid
     */
    private void checkSignerValidity(Admin admin, CAData signcadata) throws UnsupportedEncodingException, IllegalKeyStoreException {
        // Check validity of signers certificate
        Certificate signcert = (Certificate) signcadata.getCA().getCACertificate();
        try {
            CertTools.checkValidity(signcert, new Date());
        } catch (CertificateExpiredException ce) {
            // Signers Certificate has expired.
            signcadata.setStatus(SecConst.CA_EXPIRED);
            String msg = intres.getLocalizedMessage("signsession.caexpired", signcadata.getSubjectDN());
            logSession.log(admin, signcadata.getCaId().intValue(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED,
                    msg, ce);
            throw new EJBException(ce);
        } catch (CertificateNotYetValidException cve) {
            String msg = intres.getLocalizedMessage("signsession.canotyetvalid", signcadata.getSubjectDN());
            logSession.log(admin, signcadata.getCaId().intValue(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CAEDITED,
                    msg, cve);
            throw new EJBException(cve);
        }
    }

    /**
     * Helper method that activates CA services and publisher their
     * certificates, if the services are marked as active
     */
    private void activateAndPublishExternalCAServices(Admin admin, Collection<ExtendedCAServiceInfo> extendedCAServiceInfos, CA ca) {
        // activate External CA Services
        Iterator<ExtendedCAServiceInfo> iter = extendedCAServiceInfos.iterator();
        while (iter.hasNext()) {
            ExtendedCAServiceInfo info = (ExtendedCAServiceInfo) iter.next();
            ArrayList<Certificate> certificate = new ArrayList<Certificate>();
            if (info instanceof OCSPCAServiceInfo) {
                try {
                    ca.initExternalService(ExtendedCAServiceInfo.TYPE_OCSPEXTENDEDSERVICE, ca);
                    // The OCSP certificate is the same as the CA signing
                    // certificate
                } catch (Exception fe) {
                    String msg = intres.getLocalizedMessage("caadmin.errorcreatecaservice", "OCSPCAService");
                    logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg,
                            fe);
                    throw new EJBException(fe);
                }
            }
            if (info instanceof XKMSCAServiceInfo) {
                try {
                    ca.initExternalService(ExtendedCAServiceInfo.TYPE_XKMSEXTENDEDSERVICE, ca);
                    certificate.add(((XKMSCAServiceInfo) ca.getExtendedCAServiceInfo(ExtendedCAServiceInfo.TYPE_XKMSEXTENDEDSERVICE))
                            .getXKMSSignerCertificatePath().get(0));
                } catch (Exception fe) {
                    String msg = intres.getLocalizedMessage("caadmin.errorcreatecaservice", "XKMSCAService");
                    logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg,
                            fe);
                    throw new EJBException(fe);
                }
            }
            if (info instanceof CmsCAServiceInfo) {
                try {
                    ca.initExternalService(ExtendedCAServiceInfo.TYPE_CMSEXTENDEDSERVICE, ca);
                    certificate
                            .add(((CmsCAServiceInfo) ca.getExtendedCAServiceInfo(ExtendedCAServiceInfo.TYPE_CMSEXTENDEDSERVICE)).getCertificatePath().get(0));
                } catch (Exception fe) {
                    String msg = intres.getLocalizedMessage("caadmin.errorcreatecaservice", "CMSCAService");
                    logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_CACREATED, msg,
                            fe);
                    throw new EJBException(fe);
                }
            }
            // Always store the certificate. Only publish the extended service
            // certificate for active services.
            Collection<Integer> publishers = null;
            if (info.getStatus() == ExtendedCAServiceInfo.STATUS_ACTIVE) {
                publishers = ca.getCRLPublishers();
            }
            if ((!certificate.isEmpty())) {
                publishCACertificate(admin, certificate, publishers, ca.getSubjectDN());
            }
        }
    }
}
TOP

Related Classes of org.ejbca.core.ejb.ca.caadmin.CAAdminSessionBean

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.