Package org.ejbca.core.ejb.ca.store

Source Code of org.ejbca.core.ejb.ca.store.CertificateStoreSessionBean

/*************************************************************************
*                                                                       *
*  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.store;

import java.math.BigInteger;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.security.spec.ECParameterSpec;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.ejb.CreateException;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import javax.ejb.FinderException;
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.cesecore.core.ejb.log.LogSessionLocal;
import org.ejbca.config.EjbcaConfiguration;
import org.ejbca.core.ejb.JndiHelper;
import org.ejbca.core.ejb.ca.publisher.PublisherSessionLocal;
import org.ejbca.core.model.InternalResources;
import org.ejbca.core.model.SecConst;
import org.ejbca.core.model.authorization.AuthenticationFailedException;
import org.ejbca.core.model.authorization.AuthorizationDeniedException;
import org.ejbca.core.model.ca.crl.RevokedCertInfo;
import org.ejbca.core.model.ca.store.CertReqHistory;
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.UserDataVO;
import org.ejbca.cvc.PublicKeyEC;
import org.ejbca.util.Base64;
import org.ejbca.util.CertTools;
import org.ejbca.util.StringTools;
import org.ejbca.util.keystore.KeyTools;

/**
* Stores certificate and CRL in the local database using Certificate and CRL Entity Beans.
*
* @version $Id: CertificateStoreSessionBean.java 11920 2011-05-06 13:11:06Z jeklund $
*/
@Stateless(mappedName = JndiHelper.APP_JNDI_PREFIX + "CertificateStoreSessionRemote")
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class CertificateStoreSessionBean extends CertificateDataUtil implements CertificateStoreSessionRemote, CertificateStoreSessionLocal {

    private final static Logger log = Logger.getLogger(CertificateStoreSessionBean.class);
    /** Internal localization of logs and errors */
    private static final InternalResources intres = InternalResources.getInstance();
   
    @PersistenceContext(unitName="ejbca")
    private EntityManager entityManager;

    @EJB
    private LogSessionLocal logSession;
    @EJB
    private PublisherSessionLocal publisherSession;
   
    public CertificateStoreSessionBean() {
        super();
    }
   
    @Override
    public String getDatabaseStatus() {
    String returnval = "";
    try {
      entityManager.createNativeQuery(EjbcaConfiguration.getHealthCheckDbQuery()).getResultList();
      // TODO: Do we need to flush() the connection to avoid that this is executed in a batch after the method returns?
    } catch (Exception e) {
      returnval = "\nDB: Error creating connection to database: " + e.getMessage();
      log.error("Error creating connection to database.",e);
    }
    return returnval;
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public boolean storeCertificate(Admin admin, Certificate incert, String username, String cafp,
                                    int status, int type, int certificateProfileId, String tag, long updateTime) throws CreateException {
      if (log.isTraceEnabled()) {
            log.trace(">storeCertificate(" + username + ", " + cafp + ", " + status + ", " + type + ")");
      }
        // Strip dangerous chars
        username = StringTools.strip(username);

        // We need special handling here of CVC certificate with EC keys, because they lack EC parameters in all certs except the Root certificate (CVCA)
      PublicKey pubk = incert.getPublicKey();
      if ((pubk instanceof PublicKeyEC)) {
        PublicKeyEC pkec = (PublicKeyEC) pubk;
        // The public key of IS and DV certificate (CVC) do not have any parameters so we have to do some magic to get a complete EC public key
        ECParameterSpec spec = pkec.getParams();
        if (spec == null) {
          // We need to enrich this public key with parameters
          try {
            if (cafp != null) {
              String cafingerp = cafp;
              CertificateData cacert = CertificateData.findByFingerprint(entityManager, cafp);
              if (cacert == null) {
                throw new FinderException();
              }
              String nextcafp = cacert.getCaFingerprint();
              int bar = 0; // never go more than 5 rounds, who knows what strange things can exist in the CAFingerprint column, make sure we never get stuck here
              while ((!StringUtils.equals(cafingerp, nextcafp)) && (bar++ < 5)) {
                  cacert = CertificateData.findByFingerprint(entityManager, cafp);
                  if (cacert == null) {
                    throw new FinderException();
                  }
                cafingerp = nextcafp;
                nextcafp = cacert.getCaFingerprint();
              }
            // We found a root CA certificate, hopefully ?
            PublicKey pkwithparams = cacert.getCertificate().getPublicKey();
            pubk = KeyTools.getECPublicKeyWithParams(pubk, pkwithparams);
            }
        } catch (FinderException e) {
          log.info("Can not find CA certificate with fingerprint: "+cafp);
        } catch (Exception e) {
          // This catches NoSuchAlgorithmException, NoSuchProviderException and InvalidKeySpecException and possibly something else (NPE?)
          // because we want to continue anyway
          if (log.isDebugEnabled()) {
            log.debug("Can not enrich EC public key with missing parameters: ", e);
          }
        }
        }
      } // finished with ECC key special handling
     
      // Create the certificate in one go with all parameters at once. This used to be important in EJB2.1 so the persistence layer only creates *one* single
      // insert statement. If we do a home.create and the some setXX, it will create one insert and one update statement to the database.
      // Probably not important in EJB3 anymore
      final CertificateData data1 = new CertificateData(incert, pubk, username, cafp, status, type, certificateProfileId, tag, updateTime);
      final String issuerDN = data1.getIssuerDN();
        try {
          entityManager.persist(data1);
        } catch (Exception e) {
          // For backward compatibility. We should drop the throw entirely and rely on the return value.
          CreateException ce = new CreateException();
          ce.setStackTrace(e.getStackTrace());
          throw ce;
        }
        final String msg = intres.getLocalizedMessage("store.storecert");             
        logSession.log(admin, issuerDN.hashCode(), LogConstants.MODULE_CA, new Date(), username, incert, LogConstants.EVENT_INFO_STORECERTIFICATE, msg);
        log.trace("<storeCertificate()");
        return true;
    }

    @Override
    public Collection<String> listAllCertificates(Admin admin, String issuerdn) {
      log.trace(">listAllCertificates()");
      // This method was only used from CertificateDataTest and it didn't care about the expireDate, so it will only select fingerprints now.
      return CertificateData.findFingerprintsByIssuerDN(entityManager, CertTools.stringToBCDNString(StringTools.strip(issuerdn)));
    }

    @Override
    public Collection<RevokedCertInfo> listRevokedCertInfo(Admin admin, String issuerdn, long lastbasecrldate) {
      log.trace(">listRevokedCertInfo()");
      return CertificateData.getRevokedCertInfos(entityManager, CertTools.stringToBCDNString(StringTools.strip(issuerdn)), lastbasecrldate);
    }

    @Override
    public Collection<Certificate> findCertificatesBySubjectAndIssuer(Admin admin, String subjectDN, String issuerDN) {
      if (log.isTraceEnabled()) {
          log.trace(">findCertificatesBySubjectAndIssuer(), dn='" + subjectDN + "' and issuer='" + issuerDN + "'");
      }
        // First make a DN in our well-known format
        String dn = StringTools.strip(subjectDN);
        dn = CertTools.stringToBCDNString(dn);
        String issuerdn = StringTools.strip(issuerDN);
        issuerdn = CertTools.stringToBCDNString(issuerdn);
        log.debug("Looking for cert with (transformed)DN: " + dn);
        Collection<Certificate> ret = new ArrayList<Certificate>();
        Collection<CertificateData> coll = CertificateData.findBySubjectDNAndIssuerDN(entityManager, dn, issuerdn);
        Iterator<CertificateData> iter = coll.iterator();
        while (iter.hasNext()) {
          ret.add(iter.next().getCertificate());
        }
        if (log.isTraceEnabled()) {
          log.trace("<findCertificatesBySubjectAndIssuer(), dn='" + subjectDN + "' and issuer='" + issuerDN + "'");
        }
        return ret;
    }

    @Override
    public Set<String> findUsernamesByIssuerDNAndSubjectDN(Admin admin, String issuerDN, String subjectDN) {
        if (log.isTraceEnabled()) {
            log.trace(">findUsernamesByIssuerDNAndSubjectDN(), issuer='" + issuerDN + "'");
        }
        // First make a DN in our well-known format
        final String transformedIssuerDN = CertTools.stringToBCDNString(StringTools.strip(issuerDN));
        final String transformedSubjectDN = CertTools.stringToBCDNString(StringTools.strip(subjectDN));
        if ( log.isDebugEnabled() ) {
            log.debug("Looking for user with a certificate with issuer DN(transformed) '" + transformedIssuerDN + "' and subject DN(transformed) '"+transformedSubjectDN+"'.");
        }
        try {
            return CertificateData.findUsernamesBySubjectDNAndIssuerDN(entityManager, transformedSubjectDN, transformedIssuerDN);
        } finally {
            if (log.isTraceEnabled()) {
                log.trace("<findUsernamesByIssuerDNAndSubjectDN(), issuer='" + issuerDN + "'");
            }
        }
    }

    @Override
    public Set<String> findUsernamesByIssuerDNAndSubjectKeyId(Admin admin, String issuerDN, byte subjectKeyId[]) {
        if (log.isTraceEnabled()) {
            log.trace(">findUsernamesByIssuerDNAndSubjectKeyId(), issuer='" + issuerDN + "'");
        }
        // First make a DN in our well-known format
        final String transformedIssuerDN = CertTools.stringToBCDNString(StringTools.strip(issuerDN));
        final String sSubjectKeyId = new String(Base64.encode(subjectKeyId, false));
        if ( log.isDebugEnabled() ) {
            log.debug("Looking for user with a certificate with issuer DN(transformed) '" + transformedIssuerDN + "' and SubjectKeyId '"+sSubjectKeyId+"'.");
        }
        try {
          return CertificateData.findUsernamesByIssuerDNAndSubjectKeyId(entityManager, transformedIssuerDN, sSubjectKeyId);
        } finally {
            if (log.isTraceEnabled()) {
                log.trace("<findUsernamesByIssuerDNAndSubjectKeyId(), issuer='" + issuerDN + "'");
            }
        }
    }

    @Override
    public Collection<Certificate> findCertificatesBySubject(Admin admin, String subjectDN) {
      if (log.isTraceEnabled()) {
          log.trace(">findCertificatesBySubject(), dn='" + subjectDN + "'");
      }
        // First make a DN in our well-known format
        String dn = StringTools.strip(subjectDN);
        dn = CertTools.stringToBCDNString(dn);
        log.debug("Looking for cert with (transformed)DN: " + dn);
        Collection<Certificate> ret = new ArrayList<Certificate>();
        Collection<CertificateData> coll = CertificateData.findBySubjectDN(entityManager, dn);
        Iterator<CertificateData> iter = coll.iterator();
        while (iter.hasNext()) {
          ret.add(iter.next().getCertificate());
        }
        if (log.isTraceEnabled()) {
          log.trace("<findCertificatesBySubject(), dn='" + subjectDN + "'");
        }
        return ret;
    }

    @Override
    public Collection<Certificate> findCertificatesByExpireTimeWithLimit(Admin admin, Date expireTime) {
      if (log.isTraceEnabled()) {
          log.trace(">findCertificatesByExpireTimeWithLimit(), time=" + expireTime);
      }
        // First make expiretime in well know format
        log.debug("Looking for certs that expire before: " + expireTime);
        Collection<CertificateData> coll = CertificateData.findByExpireDateWithLimit(entityManager, expireTime.getTime());
        Collection<Certificate> ret = new ArrayList<Certificate>();
        if (log.isDebugEnabled()) {
          log.debug("Found "+coll.size()+" certificates that expire before "+expireTime);               
        }
        Iterator<CertificateData> iter = coll.iterator();
        while (iter.hasNext()) {
          ret.add(iter.next().getCertificate());
        }
        if (log.isTraceEnabled()) {
          log.trace("<findCertificatesByExpireTimeWithLimit(), time=" + expireTime);
        }
        return ret;
    }

    @Override
    public Collection<String>  findUsernamesByExpireTimeWithLimit(Admin admin, Date expiretime) {
      if (log.isTraceEnabled()) {
          log.trace(">findCertificatesByExpireTimeWithLimit: "+expiretime);       
      }
      return CertificateData.findUsernamesByExpireTimeWithLimit(entityManager, new Date().getTime(), expiretime.getTime());
    }

    @Override
    public Certificate findCertificateByIssuerAndSerno(Admin admin, String issuerDN, BigInteger serno) {
      return findCertificateByIssuerAndSerno(admin, issuerDN, serno, entityManager);
    }

    @Override
    public CertificateInfo findFirstCertificateInfo(final String issuerDN, final BigInteger serno) {
      return CertificateData.findFirstCertificateInfo(entityManager, CertTools.stringToBCDNString(issuerDN), serno.toString());
    }

    @Override
    public Collection<Certificate> findCertificatesByIssuerAndSernos(Admin admin, String issuerDN, Collection<BigInteger> sernos) {
      log.trace(">findCertificatesByIssuerAndSernos()");
        List<Certificate> ret = null;
        if (null == admin) {
            throw new IllegalArgumentException()// TODO: Either check authorization properly or skip the Admin parameter.. this is just wrong..
        }
        if (null == issuerDN || issuerDN.length() <= 0 || null == sernos || sernos.isEmpty()) {
            ret = new ArrayList<Certificate>();
        } else {
            String dn = CertTools.stringToBCDNString(issuerDN);
            if (log.isDebugEnabled()) {
                log.debug("Looking for cert with (transformed)DN: " + dn);
            }
            ret = CertificateData.findCertificatesByIssuerDnAndSerialNumbers(entityManager, dn, sernos);
        }
        log.trace("<findCertificatesByIssuerAndSernos()");
        return ret;
    }

    @Override
    public Collection<Certificate> findCertificatesBySerno(Admin admin, BigInteger serno) {
      if (log.isTraceEnabled()) {
          log.trace(">findCertificatesBySerno(),  serno=" + serno);
      }
      ArrayList<Certificate> ret = new ArrayList<Certificate>();
      Collection<CertificateData> coll = CertificateData.findBySerialNumber(entityManager, serno.toString());
      Iterator<CertificateData> iter = coll.iterator();
      while (iter.hasNext()) {
        ret.add(iter.next().getCertificate());
      }
      if (log.isTraceEnabled()) {
        log.trace("<findCertificatesBySerno(), serno=" + serno);
      }
      return ret;
    }

    @Override
    public String findUsernameByCertSerno(final Admin admin, final BigInteger serno, final String issuerdn) {
      if (log.isTraceEnabled()) {
        log.trace(">findUsernameByCertSerno(), serno: " + serno.toString(16) + ", issuerdn: " + issuerdn);       
      }
      final String ret = CertificateData.findLastUsernameByIssuerDNSerialNumber(entityManager, CertTools.stringToBCDNString(issuerdn), serno.toString());
        if (log.isTraceEnabled()) {
          log.trace("<findUsernameByCertSerno(), ret=" + ret);
        }
        return ret;
    }

    @Override
    public Collection<Certificate> findCertificatesByUsername(Admin admin, String username) {
      return findCertificatesByUsername(admin, username, entityManager);
    }

    @Override
    public Collection<Certificate> findCertificatesByUsernameAndStatus(Admin admin, String username, int status) {
      if (log.isTraceEnabled()) {
          log.trace(">findCertificatesByUsernameAndStatus(),  username=" + username);
      }
        ArrayList<Certificate> ret = new ArrayList<Certificate>();
        // Strip dangerous chars
        username = StringTools.strip(username);
        // This method on the entity bean does the ordering in the database
        Collection<CertificateData> coll = CertificateData.findByUsernameAndStatus(entityManager, username, status);
        Iterator<CertificateData> iter = coll.iterator();
        while (iter.hasNext()) {
          ret.add(iter.next().getCertificate());
        }
      if (log.isTraceEnabled()) {
            log.trace("<findCertificatesByUsernameAndStatus(), username=" + username);
      }
        return ret;
    }

    @Override
    public CertificateInfo getCertificateInfo(Admin admin, String fingerprint) {
      // TODO: Either enforce authorization check or drop the Admin parameter
      if (log.isTraceEnabled()) {
        log.trace(">getCertificateInfo(): "+fingerprint);
      }
      return CertificateData.getCertificateInfo(entityManager, fingerprint);
    }

    @Override
    public Certificate findCertificateByFingerprint(Admin admin, String fingerprint) {
        return findCertificateByFingerprint(admin, fingerprint, entityManager);
    }

    @Override
    public Collection<Certificate> findCertificatesByType(Admin admin, int type, String issuerDN) throws IllegalArgumentException {
        return findCertificatesByType(admin, type, issuerDN, entityManager);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public void setArchivedStatus(Admin admin, String fingerprint) throws AuthorizationDeniedException {
      if (admin.getAdminType() != Admin.TYPE_INTERNALUSER) {
        throw new AuthorizationDeniedException("Unauthorized");
      }
      CertificateData rev = CertificateData.findByFingerprint(entityManager, fingerprint);
      if (rev != null) {
        rev.setStatus(SecConst.CERT_ARCHIVED);
        if (log.isDebugEnabled()) {
          log.debug("Set status ARCHIVED for certificate with fp: "+fingerprint+", revocation reason is: "+rev.getRevocationReason());
        }
      } else {
        String msg = intres.getLocalizedMessage("store.errorcertinfo", fingerprint);             
        logSession.log(admin, 0, LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_UNKNOWN, msg);
        throw new EJBException(msg);
      }
    }
   
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public void setRevokeStatus(Admin admin, String issuerdn, BigInteger serno, Collection<Integer> publishers, int reason, String userDataDN) {
      setRevokeStatus(admin, issuerdn, serno, new Date(), publishers, reason, userDataDN);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public void setRevokeStatus(Admin admin, String issuerdn, BigInteger serno, Date revokedate, Collection<Integer> publishers, int reason, String userDataDN) {
      if (log.isTraceEnabled()) {
          log.trace(">setRevokeStatus(),  issuerdn=" + issuerdn + ", serno=" + serno.toString(16)+", reason="+reason);
      }
        try {
          Certificate certificate = findCertificateByIssuerAndSerno(admin, issuerdn, serno);
          setRevokeStatus(admin, certificate, revokedate, publishers, reason, userDataDN);
        } catch (FinderException e) {
          String msg = intres.getLocalizedMessage("store.errorfindcertserno", serno.toString(16));             
            logSession.log(admin, issuerdn.hashCode(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_REVOKEDCERT, msg);
            throw new EJBException(e);
        }
      if (log.isTraceEnabled()) {
            log.trace("<setRevokeStatus(),  issuerdn=" + issuerdn + ", serno=" + serno.toString(16)+", reason="+reason);
      }
    }

    /**
     * Helper method to set the status of certificate to revoked or active. Re-activating (unrevoking) a certificate have two limitations.
     * 1. A password (for for example AD) will not be restored if deleted, only the certificate and certificate status and associated info will be restored
     * 2. ExtendedInformation, if used by a publisher will not be used when re-activating a certificate
     *
     * The method leaves up to the caller to find the correct publishers and userDataDN.
     *
     * @param admin      Administrator performing the operation
     * @param certificate the certificate to revoke or activate.
     * @param publishers and array of publiserids (Integer) of publishers to revoke/re-publish the certificate in.
     * @param reason     the reason of the revocation. (One of the RevokedCertInfo.REVOCATION_REASON constants.)
     * @param userDataDN if an DN object is not found in the certificate use object from user data instead.
     * @throws FinderException
     */
    private void setRevokeStatus(Admin admin, Certificate certificate, Date revokedate, Collection<Integer> publishers, int reason, String userDataDN) throws FinderException {
      if (certificate == null) {
        return;
      }
      if (log.isTraceEnabled()) {
          log.trace(">private setRevokeStatus(Certificate),  issuerdn=" + CertTools.getIssuerDN(certificate) + ", serno=" + CertTools.getSerialNumberAsString(certificate));
      }
      CertificateData rev = CertificateData.findByFingerprint(entityManager, CertTools.getFingerprintAsString(certificate));
      if (rev == null) {
        throw new FinderException("No certificate with fingerprint " + CertTools.getFingerprintAsString(certificate));
      }
      String username = rev.getUsername();
      String cafp = rev.getCaFingerprint();
      int type = rev.getType();
      Date now = new Date();
      final int caid = rev.getIssuerDN().hashCode();
     
      // A normal revocation
      if ( (rev.getStatus() != SecConst.CERT_REVOKED)
          && (reason != RevokedCertInfo.NOT_REVOKED) && (reason != RevokedCertInfo.REVOCATION_REASON_REMOVEFROMCRL) ) {
        rev.setStatus(SecConst.CERT_REVOKED);
        rev.setRevocationDate(revokedate);
        rev.setUpdateTime(now.getTime());
        rev.setRevocationReason(reason);               
        String msg = intres.getLocalizedMessage("store.revokedcert", Integer.valueOf(reason));             
        logSession.log(admin, caid, LogConstants.MODULE_CA, new Date(), null, certificate, LogConstants.EVENT_INFO_REVOKEDCERT, msg);
        // Revoke in all related publishers
        publisherSession.revokeCertificate(admin, publishers, certificate, username, userDataDN, cafp, type, reason, revokedate.getTime(), rev.getTag(), rev.getCertificateProfileId(), now.getTime());
            // Unrevoke, can only be done when the certificate was previously revoked with reason CertificateHold
      } else if ( ((reason == RevokedCertInfo.NOT_REVOKED) || (reason == RevokedCertInfo.REVOCATION_REASON_REMOVEFROMCRL))
          && (rev.getRevocationReason() == RevokedCertInfo.REVOCATION_REASON_CERTIFICATEHOLD) ) {
        // Only allow unrevocation if the certificate is revoked and the revocation reason is CERTIFICATE_HOLD
        int status = SecConst.CERT_ACTIVE;
        rev.setStatus(status);
        long revocationDate = -1L; // A null Date to setRevocationDate will result in -1 stored in long column
        rev.setRevocationDate(null);
        rev.setUpdateTime(now.getTime());
        int revocationReason = RevokedCertInfo.NOT_REVOKED;
        rev.setRevocationReason(revocationReason);
        // Republish the certificate if possible
        // Republishing will not restore a password, for example in AD, it will only re-activate the certificate.
        String password = null;
        boolean published = publisherSession.storeCertificate(admin, publishers, certificate, username, password, userDataDN,
            cafp, status, type, revocationDate, revocationReason, rev.getTag(), rev.getCertificateProfileId(), now.getTime(), null);
        if (published) {
          final String msg = intres.getLocalizedMessage("store.republishunrevokedcert", Integer.valueOf(reason));             
          logSession.log(admin, caid, LogConstants.MODULE_CA, new Date(), null, certificate, LogConstants.EVENT_INFO_NOTIFICATION, msg);
        } else {
            // If it is not possible, only log error but continue the operation of not revoking the certificate
          final String msg = "Unrevoked cert:" + CertTools.getSerialNumberAsString(certificate) + " reason: " + reason + " Could not be republished.";
          logSession.log(admin, caid, LogConstants.MODULE_CA, new Date(), null, certificate, LogConstants.EVENT_INFO_NOTIFICATION, msg);
        }
      } else {
        String msg = intres.getLocalizedMessage("store.ignorerevoke", CertTools.getSerialNumberAsString(certificate), Integer.valueOf(rev.getStatus()), Integer.valueOf(reason));             
        logSession.log(admin, caid, LogConstants.MODULE_CA, new Date(), null, certificate, LogConstants.EVENT_INFO_NOTIFICATION, msg);
      }
      if (log.isTraceEnabled()) {
          log.trace("<private setRevokeStatus(),  issuerdn=" + CertTools.getIssuerDN(certificate) + ", serno=" + CertTools.getSerialNumberAsString(certificate));
      }
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public void revokeCertificate(Admin admin, Certificate cert, Collection<Integer> publishers, int reason, String userDataDN) {
        if (cert instanceof X509Certificate) {
            setRevokeStatus(admin, CertTools.getIssuerDN(cert), CertTools.getSerialNumber(cert), publishers, reason, userDataDN);
        }
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    // TODO: Does not publish revocations to publishers!!!
  // TODO: Enforce or drop Admin parameter
    public void revokeAllCertByCA(Admin admin, String issuerdn, int reason) {
        int temprevoked = 0;
        int revoked = 0;
        String bcdn = CertTools.stringToBCDNString(issuerdn);
        try {
            // Change all temporaty revoked certificates to permanently revoked certificates
          temprevoked = CertificateData.revokeOnHoldPermanently(entityManager, bcdn);
            // Revoking all non revoked certificates.
          revoked = CertificateData.revokeAllNonRevokedCertificates(entityManager, bcdn, reason);
        String msg = intres.getLocalizedMessage("store.revokedallbyca", issuerdn, Integer.valueOf(revoked + temprevoked), Integer.valueOf(reason));             
            logSession.log(admin, bcdn.hashCode(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_REVOKEDCERT, msg);
        } catch (Exception e) {
        String msg = intres.getLocalizedMessage("store.errorrevokeallbyca", issuerdn);             
            logSession.log(admin, bcdn.hashCode(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_REVOKEDCERT, msg, e);
            throw new EJBException(e);
        }
    }

    @Override
    public boolean checkIfAllRevoked(Admin admin, String username) {
        boolean returnval = true;
        Certificate certificate = null;
        // Strip dangerous chars
        username = StringTools.strip(username);
        Collection<Certificate> certs = findCertificatesByUsername(admin, username);
        // Revoke all certs
        if (!certs.isEmpty()) {
          Iterator<Certificate> j = certs.iterator();
          while (j.hasNext()) {
            certificate = j.next();
            String fingerprint = CertTools.getFingerprintAsString(certificate);
            CertificateInfo info = getCertificateInfo(admin, fingerprint);
            if (info != null && info.getStatus() != SecConst.CERT_REVOKED) {
              returnval = false;
              break;
            }
          }
        }
        return returnval;
    }

    @Override
    public boolean isRevoked(String issuerDN, BigInteger serno) {
        if (log.isTraceEnabled()) {
          log.trace(">isRevoked(), dn:" + issuerDN + ", serno=" + serno.toString(16));
        }
        // First make a DN in our well-known format
        String dn = CertTools.stringToBCDNString(issuerDN);
        boolean ret = false;
        try {
          Collection<CertificateData> coll = CertificateData.findByIssuerDNSerialNumber(entityManager, dn, serno.toString());
            if (coll.size() > 0) {
                if (coll.size() > 1) {
                    String msg = intres.getLocalizedMessage("store.errorseveralissuerserno", issuerDN, serno.toString(16));            
                    //adapter.log(admin, issuerDN.hashCode(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_DATABASE, msg);
                    log.error(msg);
                }
                Iterator<CertificateData> iter = coll.iterator();
                while (iter.hasNext()) {
                    CertificateData data = iter.next();
                    // if any of the certificates with this serno is revoked, return true
                    if (data.getStatus() == SecConst.CERT_REVOKED) {
                      ret = true;
                      break;
                    }
                }
            } else {
                // If there are no certificates with this serial number, return true (=revoked). Better safe than sorry!
              ret = true;
              if (log.isTraceEnabled()) {
                log.trace("isRevoked() did not find certificate with dn "+dn+" and serno "+serno.toString(16));
              }
            }
        } catch (Exception e) {
            throw new EJBException(e);
        }
        if (log.isTraceEnabled()) {
          log.trace("<isRevoked() returned " + ret);
        }
        return ret;
    }

    @Override
    public CertificateStatus getStatus(String issuerDN, BigInteger serno) {
        return getStatus(issuerDN, serno, entityManager);
    }

    @Override
    public void authenticate(X509Certificate certificate, boolean requireAdminCertificateInDatabase) throws AuthenticationFailedException {
        // Check Validity
        try {
            certificate.checkValidity();
        } catch (Exception e) {
          String msg = intres.getLocalizedMessage("authentication.certexpired", CertTools.getNotAfter(certificate).toString());             
            throw new AuthenticationFailedException(msg);
        }
        if (requireAdminCertificateInDatabase) {
            // TODO: Verify Signature on cert? Not really needed since it's one of ou certs in the database.
            // Check if certificate is revoked.
            boolean isRevoked = isRevoked(CertTools.getIssuerDN(certificate),CertTools.getSerialNumber(certificate));
            if (isRevoked) {
                // Certificate revoked or missing in the database
              String msg = intres.getLocalizedMessage("authentication.revokedormissing");             
                throw new AuthenticationFailedException(msg);
            }
        } else {
          // TODO: We should check the certificate for CRL or OCSP tags and verify the certificate status
        }
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public void addCertReqHistoryData(Admin admin, Certificate cert, UserDataVO useradmindata){
      final String issuerDN = CertTools.getIssuerDN(cert);
      final String username = useradmindata.getUsername();
      if (log.isTraceEnabled()) {
          log.trace(">addCertReqHistoryData(" + CertTools.getSerialNumberAsString(cert) + ", " + issuerDN + ", " + username + ")");
      }
        try {
          entityManager.persist(new CertReqHistoryData(cert, issuerDN, useradmindata));
          final String msg = intres.getLocalizedMessage("store.storehistory", username);             
            logSession.log(admin, issuerDN.hashCode(), LogConstants.MODULE_CA, new Date(), username, cert, LogConstants.EVENT_INFO_STORECERTIFICATE, msg);           
        } catch (Exception e) {
          final String msg = intres.getLocalizedMessage("store.errorstorehistory", useradmindata.getUsername());             
            logSession.log(admin, issuerDN.hashCode(), LogConstants.MODULE_CA, new Date(), username, cert, LogConstants.EVENT_ERROR_STORECERTIFICATE, msg);
            throw new EJBException(e);
        }
      if (log.isTraceEnabled()) {
        log.trace("<addCertReqHistoryData()");
        }
    }
   
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public void removeCertReqHistoryData(Admin admin, String certFingerprint){
      if (log.isTraceEnabled()) {
          log.trace(">removeCertReqHistData(" + certFingerprint + ")");
      }
        try {         
          String msg = intres.getLocalizedMessage("store.removehistory", certFingerprint);             
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_INFO_STORECERTIFICATE, msg);
            CertReqHistoryData crh = CertReqHistoryData.findById(entityManager, certFingerprint);
            if (crh == null) {
              if (log.isDebugEnabled()) {
                log.debug("Trying to remove CertReqHistory that does not exist: "+certFingerprint);                   
              }
            } else {
              entityManager.remove(crh);
            }
        } catch (Exception e) {
          String msg = intres.getLocalizedMessage("store.errorremovehistory", certFingerprint);             
            logSession.log(admin, admin.getCaId(), LogConstants.MODULE_CA, new java.util.Date(), null, null, LogConstants.EVENT_ERROR_STORECERTIFICATE, msg);
            throw new EJBException(e);
        }
        log.trace("<removeCertReqHistData()");        
    }
   
    // getCertReqHistory() might perform database updates, so we always need to run this in a transaction
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public CertReqHistory getCertReqHistory(Admin admin, BigInteger certificateSN, String issuerDN){
      CertReqHistory retval = null;
      Collection<CertReqHistoryData> result = CertReqHistoryData.findByIssuerDNSerialNumber(entityManager, issuerDN, certificateSN.toString());
      if(result.iterator().hasNext()) {
        retval = result.iterator().next().getCertReqHistory();
      }
      return retval;
    }

    // getCertReqHistory() might perform database updates, so we always need to run this in a transaction
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public List<CertReqHistory> getCertReqHistory(Admin admin, String username){
      ArrayList<CertReqHistory> retval = new ArrayList<CertReqHistory>();
      Collection<CertReqHistoryData> result = CertReqHistoryData.findByUsername(entityManager, username);
      Iterator<CertReqHistoryData> iter = result.iterator();
      while(iter.hasNext()) {
        retval.add(iter.next().getCertReqHistory());
      }
      return retval;
    }
   
    @Override
    public List<Object[]> findExpirationInfo(String cASelectString, long activeNotifiedExpireDateMin, long activeNotifiedExpireDateMax, long activeExpireDateMin) {
      return CertificateData.findExpirationInfo(entityManager, cASelectString, activeNotifiedExpireDateMin, activeNotifiedExpireDateMax, activeExpireDateMin);
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    @Override
    public boolean setStatus(String fingerprint, int status) {
      return CertificateData.updateStatus(entityManager, fingerprint, status);
    }
}
TOP

Related Classes of org.ejbca.core.ejb.ca.store.CertificateStoreSessionBean

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.