From db615a895b644af038308ae71b680f1d93f78f70 Mon Sep 17 00:00:00 2001 From: mharmsen Date: Sat, 29 Oct 2011 04:43:21 +0000 Subject: Bugzilla Bug #737761 - Update Dogtag Packages for Fedora 16 git-svn-id: svn+ssh://svn.fedorahosted.org/svn/pki/tags/DOGTAG_9_0_FEDORA_15_16_17_20111028@2279 c9f7a03b-bd48-0410-a16d-cbbf54688b0b --- .../ca/src/com/netscape/ca/CRLIssuingPoint.java | 3086 ++++++++++++++++++++ 1 file changed, 3086 insertions(+) create mode 100644 pki/base/ca/src/com/netscape/ca/CRLIssuingPoint.java (limited to 'pki/base/ca/src/com/netscape/ca/CRLIssuingPoint.java') diff --git a/pki/base/ca/src/com/netscape/ca/CRLIssuingPoint.java b/pki/base/ca/src/com/netscape/ca/CRLIssuingPoint.java new file mode 100644 index 000000000..aba2db149 --- /dev/null +++ b/pki/base/ca/src/com/netscape/ca/CRLIssuingPoint.java @@ -0,0 +1,3086 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package com.netscape.ca; + + +import java.util.*; +import java.math.*; +import java.io.*; +import java.security.cert.CRLException; +import java.security.NoSuchAlgorithmException; +import netscape.security.x509.*; +import netscape.security.util.*; +import netscape.security.pkcs.*; +import com.netscape.certsrv.base.*; +import com.netscape.certsrv.util.*; +import com.netscape.certsrv.request.*; +import com.netscape.certsrv.security.*; +import com.netscape.certsrv.common.*; +import com.netscape.certsrv.logging.*; +import com.netscape.certsrv.ca.*; +import com.netscape.certsrv.dbs.*; +import com.netscape.certsrv.dbs.crldb.*; +import com.netscape.cmscore.dbs.*; +import com.netscape.certsrv.dbs.crldb.ICRLRepository; +import com.netscape.certsrv.dbs.certdb.*; +import com.netscape.certsrv.ldap.*; +import com.netscape.certsrv.publish.*; +import com.netscape.certsrv.apps.*; +import com.netscape.certsrv.ca.ICMSCRLExtension; +import com.netscape.cmscore.request.CertRequestConstants; +import com.netscape.cmscore.ldap.*; +import com.netscape.cmscore.util.Debug; + +/** + * This class encapsulates CRL issuing mechanism. CertificateAuthority + * contains a map of CRLIssuingPoint indexed by string ids. Each issuing + * point contains information about CRL issuing and publishing parameters + * as well as state information which includes last issued CRL, next CRL + * serial number, time of the next update etc. + * If autoUpdateInterval is set to non-zero value then worker thread + * is created that will perform CRL update at scheduled intervals. Update + * can also be triggered by invoking updateCRL method directly. Another + * parameter minUpdateInterval can be used to prevent CRL + * from being updated too often + *

+ * + * @author awnuk + * @author lhsiao + * @author galperin + * @version $Revision$, $Date$ + */ + +public class CRLIssuingPoint implements ICRLIssuingPoint, Runnable { + + /* Foreign config param for IssuingDistributionPointExtension. */ + public static final String PROP_CACERTS = "onlyContainsCACerts"; + + public static final long SECOND = 1000L; + public static final long MINUTE = (SECOND * 60L); + + private static final int CRL_PAGE_SIZE = 10000; + + /* configuration file property names */ + + public IPublisherProcessor mPublisherProcessor = null; + + private ILogger mLogger = CMS.getLogger(); + + private IConfigStore mConfigStore; + + private ICRLPublisher mCRLPublisher = null; + private int mCountMod = 0; + private int mCount = 0; + private int mPageSize = CRL_PAGE_SIZE; + + private CMSCRLExtensions mCMSCRLExtensions = null; + + /** + * Internal unique id of this CRL issuing point. + */ + protected String mId = null; + + /** + * Reference to the CertificateAuthority instance which owns this + * issuing point. + */ + protected ICertificateAuthority mCA = null; + + /** + * Reference to the CRL repository maintained in CA. + */ + protected ICRLRepository mCRLRepository = null; + + /** + * Reference to the cert repository maintained in CA. + */ + private ICertificateRepository mCertRepository = null; + + /** + * Enable CRL issuing point. + */ + private boolean mEnable = true; + + /** + * Description of the issuing point + */ + private String mDescription = null; + + /** + * CRL cache + */ + private Hashtable mCRLCerts = new Hashtable(); + private Hashtable mRevokedCerts = new Hashtable(); + private Hashtable mUnrevokedCerts = new Hashtable(); + private Hashtable mExpiredCerts = new Hashtable(); + private boolean mIncludeExpiredCerts = false; + private boolean mIncludeExpiredCertsOneExtraTime = false; + private boolean mCACertsOnly = false; + + private boolean mProfileCertsOnly = false; + private Vector mProfileList = null; + + /** + * Enable CRL cache. + */ + private boolean mEnableCRLCache = true; + private boolean mCRLCacheIsCleared = true; + private boolean mEnableCacheRecovery = false; + private String mFirstUnsaved = null; + private boolean mEnableCacheTesting = false; + + /** + * Last CRL cache update + */ + private long mLastCacheUpdate = 0; + + /** + * Time interval in milliseconds between consequential CRL cache + * updates performed automatically. + */ + private long mCacheUpdateInterval; + + /** + * Enable CRL updates. + */ + private boolean mEnableCRLUpdates = true; + + /** + * CRL update schema. + */ + private int mUpdateSchema = 1; + private int mSchemaCounter = 0; + + /** + * Enable CRL daily updates at listed times. + */ + private boolean mEnableDailyUpdates = false; + private Vector mDailyUpdates = null; + private int mCurrentDay = 0; + private int mLastDay = 0; + private int mTimeListSize = 0; + private boolean mExtendedTimeList = false; + + /** + * Enable CRL auto update with interval + */ + private boolean mEnableUpdateFreq = false; + + /** + * Time interval in milliseconds between consequential CRL Enable CRL daily update at updates + * performed automatically. + */ + private long mAutoUpdateInterval; + + /** + * Minimum time interval in milliseconds between consequential + * CRL updates (manual or automatic). + */ + private long mMinUpdateInterval; + + /** + * Update CRL even if auto interval > 0 + */ + private boolean mAlwaysUpdate = false; + + /** + * next update grace period + */ + private long mNextUpdateGracePeriod; + + /** + * Boolean flag controlling whether CRLv2 extensions are to be + * used in CRL. + */ + private boolean mAllowExtensions = false; + + /** + * DN of the directory entry where CRLs from this issuing point + * are published. + */ + private String mPublishDN = null; + + /** + * signing algorithm + */ + private String mSigningAlgorithm = null; + private String mLastSigningAlgorithm = null; + + /** + * Cached value of the CRL extensions to be placed in CRL + */ + //protected CRLExtensions mCrlExtensions; + + /** + * CRL number + */ + private BigInteger mCRLNumber; + private BigInteger mNextCRLNumber; + private BigInteger mLastCRLNumber; + + /** + * Delta CRL number + */ + private BigInteger mDeltaCRLNumber; + private BigInteger mNextDeltaCRLNumber; + + /** + * Last CRL update date + */ + private Date mLastUpdate; + private Date mLastFullUpdate; + private long mLastScheduledUpdate = 0; + + /** + * Next scheduled CRL update date + */ + private Date mNextUpdate; + private Date mNextDeltaUpdate; + private boolean mExtendedNextUpdate; + + /** + * Worker thread doing auto-update + */ + private Thread mUpdateThread = null; + + /** + * for going one more round when auto-interval is set to 0 (turned off) + */ + private boolean mDoLastAutoUpdate = false; + + /** + * whether issuing point has been initialized. + */ + private int mInitialized = CRL_IP_NOT_INITIALIZED; + + /** + * number of entries in the CRL + */ + private long mCRLSize = -1; + private long mDeltaCRLSize = -1; + + /** + * update status, publishing status Strings to store in requests to + * display result. + */ + private String mCrlUpdateStatus; + private String mCrlUpdateError; + private String mCrlPublishStatus; + private String mCrlPublishError; + + /** + * begin, end serial number range of revoked certs if any. + */ + protected BigInteger mBeginSerial = null; + protected BigInteger mEndSerial = null; + + private int mUpdatingCRL = CRL_UPDATE_DONE; + + private boolean mDoManualUpdate = false; + private String mSignatureAlgorithmForManualUpdate = null; + + private boolean mPublishOnStart = false; + private long[] mSplits = new long[10]; + + private boolean mSaveMemory = false; + + /** + * Constructs a CRL issuing point from instantiating from class name. + * CRL Issuing point must be followed by method call init(CA, id, config); + */ + public CRLIssuingPoint() { + } + + public boolean isCRLIssuingPointEnabled() { + return mEnable; + } + + public void enableCRLIssuingPoint(boolean enable) { + if ((!enable) && (mEnable ^ enable)) { + clearCRLCache(); + updateCRLCacheRepository(); + } + mEnable = enable; + setAutoUpdates(); + } + + public boolean isCRLGenerationEnabled() { + return mEnableCRLUpdates; + } + + public String getCrlUpdateStatusStr() { + return mCrlUpdateStatus; + } + + public String getCrlUpdateErrorStr() { + return mCrlUpdateError; + } + + public String getCrlPublishStatusStr() { + return mCrlPublishStatus; + } + + public String getCrlPublishErrorStr() { + return mCrlPublishError; + } + + public ICMSCRLExtensions getCRLExtensions() { + return mCMSCRLExtensions; + } + + public int isCRLIssuingPointInitialized() { + return mInitialized; + } + + public boolean isManualUpdateSet() { + return mDoManualUpdate; + } + + public boolean areExpiredCertsIncluded() { + return mIncludeExpiredCerts; + } + + public boolean isCACertsOnly() { + return mCACertsOnly; + } + + public boolean isProfileCertsOnly() { + return (mProfileCertsOnly && mProfileList != null && mProfileList.size() > 0); + } + + public boolean checkCurrentProfile(String id) { + boolean b = false; + + if (mProfileCertsOnly && mProfileList != null && mProfileList.size() > 0) { + for (int k = 0; k < mProfileList.size(); k++) { + String profileId = (String) mProfileList.elementAt(k); + if (id != null && profileId != null && profileId.equalsIgnoreCase(id)) { + b = true; + break; + } + } + } + + return b; + } + + + /** + * Initializes a CRL issuing point config. + *

+ * + * @param ca reference to CertificateAuthority instance which + * owns this issuing point. + * @param id string id of this CRL issuing point. + * @param config configuration of this CRL issuing point. + * @exception EBaseException if initialization failed + * @exception IOException + */ + public void init(ISubsystem ca, String id, IConfigStore config) + throws EBaseException { + mCA = (ICertificateAuthority) ca; + mId = id; + + if (mId.equals(ICertificateAuthority.PROP_MASTER_CRL)) { + mCrlUpdateStatus = IRequest.CRL_UPDATE_STATUS; + mCrlUpdateError = IRequest.CRL_UPDATE_ERROR; + mCrlPublishStatus = IRequest.CRL_PUBLISH_STATUS; + mCrlPublishError = IRequest.CRL_PUBLISH_ERROR; + } else { + mCrlUpdateStatus = IRequest.CRL_UPDATE_STATUS + "_" + mId; + mCrlUpdateError = IRequest.CRL_UPDATE_ERROR + "_" + mId; + mCrlPublishStatus = IRequest.CRL_PUBLISH_STATUS + "_" + mId; + mCrlPublishError = IRequest.CRL_PUBLISH_ERROR + "_" + mId; + } + + mConfigStore = config; + + IConfigStore crlSubStore = mCA.getConfigStore().getSubStore(mCA.PROP_CRL_SUBSTORE); + mPageSize = crlSubStore.getInteger(mCA.PROP_CRL_PAGE_SIZE, CRL_PAGE_SIZE); + CMS.debug("CRL Page Size: "+ mPageSize); + + mCountMod = config.getInteger("countMod",0); + mCRLRepository = mCA.getCRLRepository(); + mCertRepository = mCA.getCertificateRepository(); + ((CertificateRepository) mCertRepository).addCRLIssuingPoint(mId, this); + mPublisherProcessor = mCA.getPublisherProcessor(); + + //mCRLPublisher = mCA.getCRLPublisher(); + ((CAService) mCA.getCAService()).addCRLIssuingPoint(mId, this); + + // read in config parameters. + initConfig(config); + + // create request listener. + String lname = RevocationRequestListener.class.getName(); + String crlListName = lname + "_" + mId; + + if (mCA.getRequestListener(crlListName) == null) { + mCA.registerRequestListener( + crlListName, new RevocationRequestListener()); + } + + for (int i = 0; i < mSplits.length; i++) { + mSplits[i] = 0; + } + + // this will start a thread if necessary for automatic updates. + setAutoUpdates(); + } + + + private int checkTime(String time) { + String digits = "0123456789"; + + int len = time.length(); + if (len < 3 || len > 5) return -1; + + int s = time.indexOf(':'); + if (s < 0 || s > 2 || (len - s) != 3) return -1; + + int h = 0; + for (int i = 0; i < s; i++) { + h *= 10; + int k = digits.indexOf(time.charAt(i)); + if (k < 0) return -1; + h += k; + } + if (h > 23) return -1; + + int m = 0; + for (int i = s+1; i < len; i++) { + m *= 10; + int k = digits.indexOf(time.charAt(i)); + if (k < 0) return -1; + m += k; + } + if (m > 59) return -1; + + return ((h * 60) + m); + } + + private boolean areTimeListsIdentical(Vector list1, Vector list2) { + boolean identical = true; + if (list1 == null || list2 == null) identical = false; + if (identical && list1.size() != list2.size()) identical = false; + for (int i = 0; identical && i < list1.size(); i++) { + Vector times1 = (Vector)list1.elementAt(i); + Vector times2 = (Vector)list2.elementAt(i); + if (times1.size() != times2.size()) identical = false; + for (int j = 0; identical && j < times1.size(); j++) { + if ((((Integer)(times1.elementAt(j))).intValue()) != (((Integer)(times2.elementAt(j))).intValue())) { + identical = false; + } + } + } + CMS.debug("areTimeListsIdentical: identical: "+identical); + return identical; + } + + private int getTimeListDays(Vector listedDays) { + int days = (listedDays != null)? listedDays.size(): 0; + CMS.debug("getTimeListDays: "+days); + return days; + } + + private int getTimeListSize(Vector listedDays) { + int listSize = 0; + for (int i = 0; listedDays != null && i < listedDays.size(); i++) { + Vector listedTimes = (Vector)listedDays.elementAt(i); + listSize += ((listedTimes != null)? listedTimes.size(): 0); + } + CMS.debug("getTimeListSize: ListSize="+listSize); + return listSize; + } + + private boolean isTimeListExtended(String list) { + boolean extendedTimeList = true; + if (list == null || list.indexOf('*') == -1) + extendedTimeList = false; + return extendedTimeList; + } + + private Vector getTimeList(String list) { + boolean timeListPresent = false; + if (list == null || list.length() == 0) return null; + if (list.charAt(0) == ',' || list.charAt(list.length()-1) == ',') return null; + + Vector listedDays = new Vector(); + + StringTokenizer days = new StringTokenizer(list, ";", true); + int n = 0; + Vector listedTimes = null; + while (days.hasMoreTokens()) { + String dayList = days.nextToken().trim(); + if (dayList == null) continue; + + if (dayList.equals(";")) { + if (timeListPresent) { + timeListPresent = false; + } else { + listedTimes = new Vector(); + listedDays.addElement(listedTimes); + n++; + } + continue; + } else { + listedTimes = new Vector(); + listedDays.addElement(listedTimes); + timeListPresent = true; + n++; + } + int t0 = -1; + StringTokenizer times = new StringTokenizer(dayList, ","); + while (times.hasMoreTokens()) { + String time = times.nextToken(); + int k = 1; + if (time.charAt(0) == '*') { + time = time.substring(1); + k = -1; + } + int t = checkTime(time); + if (t < 0) { + return null; + } else { + if (t > t0) { + listedTimes.addElement(new Integer(k*t)); + t0 = t; + } else { + return null; + } + } + } + } + if (!timeListPresent) { + listedTimes = new Vector(); + listedDays.addElement(listedTimes); + n++; + } + + return listedDays; + } + + private String checkProfile(String id, Enumeration e) { + if (e != null) { + while (e.hasMoreElements()) { + String profileId = (String) e.nextElement(); + if (profileId != null && profileId.equalsIgnoreCase(id)) + return id; + } + } + return null; + } + + private Vector getProfileList(String list) { + Enumeration e = null; + IConfigStore pc = CMS.getConfigStore().getSubStore("profile"); + if (pc != null) e = pc.getSubStoreNames(); + if (list == null) return null; + if (list.length() > 0 && list.charAt(list.length()-1) == ',') return null; + + Vector listedProfiles = new Vector(); + + StringTokenizer elements = new StringTokenizer(list, ",", true); + int t0 = -1; + int n = 0; + while (elements.hasMoreTokens()) { + String element = elements.nextToken().trim(); + if (element == null || element.length() == 0) return null; + if (element.equals(",") && n % 2 == 0) return null; + if (n % 2 == 0) { + String id = checkProfile(element, e); + if (id != null) { + listedProfiles.addElement(id); + } + } + n++; + } + if (n % 2 == 0) return null; + + return listedProfiles; + } + + + /** + * get CRL config store info + */ + protected void initConfig(IConfigStore config) + throws EBaseException { + + mEnable = config.getBoolean(Constants.PR_ENABLE, true); + mDescription = config.getString(Constants.PR_DESCRIPTION); + + // Get CRL cache config. + mEnableCRLCache = config.getBoolean(Constants.PR_ENABLE_CACHE, true); + mCacheUpdateInterval = MINUTE * config.getInteger(Constants.PR_CACHE_FREQ, 0); + mEnableCacheRecovery = config.getBoolean(Constants.PR_CACHE_RECOVERY, false); + mEnableCacheTesting = config.getBoolean(Constants.PR_CACHE_TESTING, false); + + // check if CRL generation is enabled + mEnableCRLUpdates = config.getBoolean(Constants.PR_ENABLE_CRL, true); + + // get update schema + mUpdateSchema = config.getInteger(Constants.PR_UPDATE_SCHEMA, 1); + mSchemaCounter = 0; + + // Get always update even if updated perdically. + mAlwaysUpdate = config.getBoolean(Constants.PR_UPDATE_ALWAYS, false); + + // Get list of daily updates. + mEnableDailyUpdates = config.getBoolean(Constants.PR_ENABLE_DAILY, false); + String daily = config.getString(Constants.PR_DAILY_UPDATES, null); + mDailyUpdates = getTimeList(daily); + mExtendedTimeList = isTimeListExtended(daily); + mTimeListSize = getTimeListSize(mDailyUpdates); + if (mDailyUpdates == null || mDailyUpdates.isEmpty() || mTimeListSize == 0) { + mEnableDailyUpdates = false; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_INVALID_TIME_LIST")); + } + + // Get auto update interval in minutes. + mEnableUpdateFreq = config.getBoolean(Constants.PR_ENABLE_FREQ, true); + mAutoUpdateInterval = MINUTE * config.getInteger(Constants.PR_UPDATE_FREQ, 0); + mMinUpdateInterval = MINUTE * config.getInteger(PROP_MIN_UPDATE_INTERVAL, 0); + if (mEnableUpdateFreq && mAutoUpdateInterval > 0 && + mAutoUpdateInterval < mMinUpdateInterval) + mAutoUpdateInterval = mMinUpdateInterval; + + // get next update grace period + mNextUpdateGracePeriod = MINUTE * config.getInteger(Constants.PR_GRACE_PERIOD, 0); + + // Get V2 or V1 CRL + mAllowExtensions = config.getBoolean(Constants.PR_EXTENSIONS, false); + + mIncludeExpiredCerts = config.getBoolean(Constants.PR_INCLUDE_EXPIREDCERTS, false); + mIncludeExpiredCertsOneExtraTime = config.getBoolean(Constants.PR_INCLUDE_EXPIREDCERTS_ONEEXTRATIME, false); + mCACertsOnly = config.getBoolean(Constants.PR_CA_CERTS_ONLY, false); + mProfileCertsOnly = config.getBoolean(Constants.PR_PROFILE_CERTS_ONLY, false); + if (mProfileCertsOnly) { + String profiles = config.getString(Constants.PR_PROFILE_LIST, null); + mProfileList = getProfileList(profiles); + } + + // Get default signing algorithm. + // check if algorithm is supported. + mSigningAlgorithm = mCA.getCRLSigningUnit().getDefaultAlgorithm(); + String algorithm = config.getString(Constants.PR_SIGNING_ALGORITHM, null); + + if (algorithm != null) { + // make sure this algorithm is acceptable to CA. + mCA.getCRLSigningUnit().checkSigningAlgorithmFromName(algorithm); + mSigningAlgorithm = algorithm; + } + + mPublishOnStart = config.getBoolean(PROP_PUBLISH_ON_START, false); + // if publish dn is null then certificate will be published to + // CA's entry in the directory. + mPublishDN = config.getString(PROP_PUBLISH_DN, null); + + mSaveMemory = config.getBoolean("saveMemory", false); + + mCMSCRLExtensions = new CMSCRLExtensions(this, config); + + mExtendedNextUpdate = ((mUpdateSchema > 1 || (mEnableDailyUpdates && mExtendedTimeList)) && isDeltaCRLEnabled())? + config.getBoolean(Constants.PR_EXTENDED_NEXT_UPDATE, true): + false; + + // Get serial number ranges if any. + mBeginSerial = config.getBigInteger(PROP_BEGIN_SERIAL, null); + if (mBeginSerial != null && mBeginSerial.compareTo(BigInteger.ZERO) < 0) { + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INVALID_PROPERTY_1", + PROP_BEGIN_SERIAL, "BigInteger", "positive number")); + } + mEndSerial = config.getBigInteger(PROP_END_SERIAL, null); + if (mEndSerial != null && mEndSerial.compareTo(BigInteger.ZERO) < 0) { + throw new EBaseException( + CMS.getUserMessage("CMS_BASE_INVALID_PROPERTY_1", + PROP_END_SERIAL, "BigInteger", "positive number")); + } + } + + /** + * Reads CRL issuing point, if missing, it creates one. + * Initializes CRL cache and republishes CRL if requested + * Called from auto update thread (run()). + * Do not call it from init(), because it will block CMS on start. + */ + private void initCRL() { + ICRLIssuingPointRecord crlRecord = null; + + mLastCacheUpdate = System.currentTimeMillis() + mCacheUpdateInterval; + + try { + crlRecord = mCRLRepository.readCRLIssuingPointRecord(mId); + } catch (EDBNotAvailException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_INST_CRL", e.toString())); + mInitialized = CRL_IP_INITIALIZATION_FAILED; + return; + } catch (EBaseException e) { + // CRL was never set. + // fall to the following.. + } + + if (crlRecord != null) { + mCRLNumber = crlRecord.getCRLNumber(); + if (crlRecord.getCRLSize() != null) { + mCRLSize = crlRecord.getCRLSize().longValue(); + } + mNextCRLNumber = mCRLNumber.add(BigInteger.ONE); + + if (crlRecord.getDeltaCRLSize() != null) { + mDeltaCRLSize = crlRecord.getDeltaCRLSize().longValue(); + } + + mDeltaCRLNumber = crlRecord.getDeltaCRLNumber(); + if (mDeltaCRLNumber == null) { + mDeltaCRLNumber = mCRLNumber; // better recovery later + } else { + if (mDeltaCRLNumber.compareTo(mCRLNumber) < 0) { + mDeltaCRLNumber = mCRLNumber; + clearCRLCache(); + mDeltaCRLSize = -1L; + } + } + mNextDeltaCRLNumber = mDeltaCRLNumber.add(BigInteger.ONE); + + if (mNextDeltaCRLNumber.compareTo(mNextCRLNumber) > 0) { + mNextCRLNumber = mNextDeltaCRLNumber; + } + + mLastCRLNumber = BigInteger.ZERO; + + mLastUpdate = crlRecord.getThisUpdate(); + if (mLastUpdate == null) { + mLastUpdate = new Date(0L); + } + mLastFullUpdate = null; + + mNextUpdate = crlRecord.getNextUpdate(); + if (isDeltaCRLEnabled()) { + mNextDeltaUpdate = (mNextUpdate != null)? new Date(mNextUpdate.getTime()): null; + } + + mFirstUnsaved = crlRecord.getFirstUnsaved(); + if (Debug.on()) { + Debug.trace("initCRL CRLNumber="+mCRLNumber.toString()+" CRLSize="+mCRLSize+ + " FirstUnsaved="+mFirstUnsaved); + } + if (mFirstUnsaved == null || + (mFirstUnsaved != null && mFirstUnsaved.equals(ICRLIssuingPointRecord.NEW_CACHE))) { + clearCRLCache(); + updateCRLCacheRepository(); + } else { + byte[] crl = crlRecord.getCRL(); + + if (crl != null) { + X509CRLImpl x509crl = null; + + if (mEnableCRLCache || mPublishOnStart) { + try { + x509crl = new X509CRLImpl(crl); + } catch (Exception e) { + clearCRLCache(); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_DECODE_CRL", e.toString())); + } catch (OutOfMemoryError e) { + clearCRLCache(); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_DECODE_CRL", e.toString())); + mInitialized = CRL_IP_INITIALIZATION_FAILED; + return; + } + } + if (x509crl != null) { + mLastFullUpdate = x509crl.getThisUpdate(); + if (mEnableCRLCache) { + if (mCRLCacheIsCleared && mUpdatingCRL == CRL_UPDATE_DONE) { + mRevokedCerts = crlRecord.getRevokedCerts(); + if (mRevokedCerts == null) { + mRevokedCerts = new Hashtable(); + } + mUnrevokedCerts = crlRecord.getUnrevokedCerts(); + if (mUnrevokedCerts == null) { + mUnrevokedCerts = new Hashtable(); + } + mExpiredCerts = crlRecord.getExpiredCerts(); + if (mExpiredCerts == null) { + mExpiredCerts = new Hashtable(); + } + if (isDeltaCRLEnabled()) { + mNextUpdate = x509crl.getNextUpdate(); + } + mCRLCerts = x509crl.getListOfRevokedCertificates(); + } + if (mFirstUnsaved != null && !mFirstUnsaved.equals(ICRLIssuingPointRecord.CLEAN_CACHE)) { + recoverCRLCache(); + } else { + mCRLCacheIsCleared = false; + } + mInitialized = CRL_IP_INITIALIZED; + } + if (mPublishOnStart) { + try { + publishCRL(x509crl); + x509crl = null; + } catch (EBaseException e) { + x509crl = null; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_PUBLISH_CRL", mCRLNumber.toString(), e.toString())); + } catch (OutOfMemoryError e) { + x509crl = null; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_PUBLISH_CRL", mCRLNumber.toString(), e.toString())); + } + } + } + } + } + } + + if (crlRecord == null) { + // no crl was ever created, or crl in db is corrupted. + // create new one. + try { + crlRecord = new CRLIssuingPointRecord(mId, BigInteger.ZERO, Long.valueOf(-1), + null, null, BigInteger.ZERO, Long.valueOf(-1), + mRevokedCerts, mUnrevokedCerts, mExpiredCerts); + mCRLRepository.addCRLIssuingPointRecord(crlRecord); + mCRLNumber = BigInteger.ZERO; //BIG_ZERO; + mNextCRLNumber = BigInteger.ONE; //BIG_ONE; + mLastCRLNumber = mCRLNumber; + mDeltaCRLNumber = mCRLNumber; + mNextDeltaCRLNumber = mNextCRLNumber; + mLastUpdate = new Date(0L); + if (crlRecord != null) { + // This will trigger updateCRLNow, which will also publish CRL. + if ((mDoManualUpdate == false) && + (mEnableCRLCache || mAlwaysUpdate || + (mEnableUpdateFreq && mAutoUpdateInterval > 0))) { + mInitialized = CRL_IP_INITIALIZED; + setManualUpdate(null); + } + } + } catch (EBaseException ex) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_CREATE_CRL", ex.toString())); + mInitialized = CRL_IP_INITIALIZATION_FAILED; + return; + } + } + mInitialized = CRL_IP_INITIALIZED; + } + + private Object configMonitor = new Object(); + + public boolean updateConfig(NameValuePairs params) { + synchronized (configMonitor) { + boolean noRestart = true; + boolean modifiedSchedule = false; + + for (int i = 0; i < params.size(); i++) { + NameValuePair p = params.elementAt(i); + String name = p.getName(); + String value = p.getValue(); + + // -- Update Schema -- + if (name.equals(Constants.PR_ENABLE_CRL)) { + if (value.equals(Constants.FALSE) && mEnableCRLUpdates) { + mEnableCRLUpdates = false; + modifiedSchedule = true; + } else if (value.equals(Constants.TRUE) && (!mEnableCRLUpdates)) { + mEnableCRLUpdates = true; + modifiedSchedule = true; + } + } + + if (name.equals(Constants.PR_UPDATE_SCHEMA)) { + try { + if (value != null && value.length() > 0) { + int schema = Integer.parseInt(value.trim()); + if (mUpdateSchema != schema) { + mUpdateSchema = schema; + mSchemaCounter = 0; + modifiedSchedule = true; + } + } + } catch (NumberFormatException e) { + noRestart = false; + } + } + + if (name.equals(Constants.PR_EXTENDED_NEXT_UPDATE)) { + if (value.equals(Constants.FALSE) && mExtendedNextUpdate) { + mExtendedNextUpdate = false; + } else if (value.equals(Constants.TRUE) && (!mExtendedNextUpdate)) { + mExtendedNextUpdate = true; + } + } + + // -- Update Frequency -- + if (name.equals(Constants.PR_UPDATE_ALWAYS)) { + if (value.equals(Constants.FALSE) && mAlwaysUpdate) { + mAlwaysUpdate = false; + } else if (value.equals(Constants.TRUE) && (!mAlwaysUpdate)) { + mAlwaysUpdate = true; + } + } + + if (name.equals(Constants.PR_ENABLE_DAILY)) { + if (value.equals(Constants.FALSE) && mEnableDailyUpdates) { + mEnableDailyUpdates = false; + modifiedSchedule = true; + } else if (value.equals(Constants.TRUE) && (!mEnableDailyUpdates)) { + mEnableDailyUpdates = true; + modifiedSchedule = true; + } + } + + if (name.equals(Constants.PR_DAILY_UPDATES)) { + boolean extendedTimeList = isTimeListExtended(value); + Vector dailyUpdates = getTimeList(value); + if (mExtendedTimeList != extendedTimeList) { + mExtendedTimeList = extendedTimeList; + modifiedSchedule = true; + } + if (!areTimeListsIdentical(mDailyUpdates, dailyUpdates)) { + mCurrentDay = 0; + mLastDay = 0; + mDailyUpdates = dailyUpdates; + mTimeListSize = getTimeListSize(mDailyUpdates); + modifiedSchedule = true; + } + if (mDailyUpdates == null || mDailyUpdates.isEmpty() || mTimeListSize == 0) { + mEnableDailyUpdates = false; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_INVALID_TIME_LIST")); + } + } + + if (name.equals(Constants.PR_ENABLE_FREQ)) { + if (value.equals(Constants.FALSE) && mEnableUpdateFreq) { + mEnableUpdateFreq = false; + modifiedSchedule = true; + } else if (value.equals(Constants.TRUE) && (!mEnableUpdateFreq)) { + mEnableUpdateFreq = true; + modifiedSchedule = true; + } + } + + if (name.equals(Constants.PR_UPDATE_FREQ)) { + try { + if (value != null && value.length() > 0) { + long t = MINUTE * Long.parseLong(value.trim()); + if (mAutoUpdateInterval != t) { + mAutoUpdateInterval = t; + modifiedSchedule = true; + } + } else { + if (mAutoUpdateInterval != 0) { + mAutoUpdateInterval = 0; + modifiedSchedule = true; + } + } + } catch (NumberFormatException e) { + noRestart = false; + } + } + + if (name.equals(Constants.PR_GRACE_PERIOD)) { + try { + if (value != null && value.length() > 0) { + mNextUpdateGracePeriod = MINUTE * Long.parseLong(value.trim()); + } + } catch (NumberFormatException e) { + noRestart = false; + } + } + + // -- CRL Cache -- + if (name.equals(Constants.PR_ENABLE_CACHE)) { + if (value.equals(Constants.FALSE) && mEnableCRLCache) { + clearCRLCache(); + updateCRLCacheRepository(); + mEnableCRLCache = false; + modifiedSchedule = true; + } else if (value.equals(Constants.TRUE) && (!mEnableCRLCache)) { + clearCRLCache(); + updateCRLCacheRepository(); + mEnableCRLCache = true; + modifiedSchedule = true; + } + } + + if (name.equals(Constants.PR_CACHE_FREQ)) { + try { + if (value != null && value.length() > 0) { + long t = MINUTE * Long.parseLong(value.trim()); + if (mCacheUpdateInterval != t) { + mCacheUpdateInterval = t; + modifiedSchedule = true; + } + } + } catch (NumberFormatException e) { + noRestart = false; + } + } + + if (name.equals(Constants.PR_CACHE_RECOVERY)) { + if (value.equals(Constants.FALSE) && mEnableCacheRecovery) { + mEnableCacheRecovery = false; + } else if (value.equals(Constants.TRUE) && (!mEnableCacheRecovery)) { + mEnableCacheRecovery = true; + } + } + + if (name.equals(Constants.PR_CACHE_TESTING)) { + if (value.equals(Constants.FALSE) && mEnableCacheTesting) { + clearCRLCache(); + updateCRLCacheRepository(); + mEnableCacheTesting = false; + setManualUpdate(null); + } else if (value.equals(Constants.TRUE) && (!mEnableCacheTesting)) { + mEnableCacheTesting = true; + } + } + + // -- CRL Format -- + if (name.equals(Constants.PR_SIGNING_ALGORITHM)) { + if (value != null) value = value.trim(); + if (!mSigningAlgorithm.equals(value)) { + mSigningAlgorithm = value; + } + } + + if (name.equals(Constants.PR_EXTENSIONS)) { + if (value.equals(Constants.FALSE) && mAllowExtensions) { + clearCRLCache(); + updateCRLCacheRepository(); + mAllowExtensions = false; + } else if (value.equals(Constants.TRUE) && (!mAllowExtensions)) { + clearCRLCache(); + updateCRLCacheRepository(); + mAllowExtensions = true; + } + } + + if (name.equals(Constants.PR_INCLUDE_EXPIREDCERTS)) { + if (value.equals(Constants.FALSE) && mIncludeExpiredCerts) { + clearCRLCache(); + updateCRLCacheRepository(); + mIncludeExpiredCerts = false; + } else if (value.equals(Constants.TRUE) && (!mIncludeExpiredCerts)) { + clearCRLCache(); + updateCRLCacheRepository(); + mIncludeExpiredCerts = true; + } + } + + if (name.equals(Constants.PR_INCLUDE_EXPIREDCERTS_ONEEXTRATIME)) { + if (value.equals(Constants.FALSE) && mIncludeExpiredCertsOneExtraTime) { + mIncludeExpiredCertsOneExtraTime = false; + } else if (value.equals(Constants.TRUE) && (!mIncludeExpiredCertsOneExtraTime)) { + mIncludeExpiredCertsOneExtraTime = true; + } + } + + if (name.equals(Constants.PR_CA_CERTS_ONLY)) { + Extension distExt = getCRLExtension(IssuingDistributionPointExtension.NAME); + IssuingDistributionPointExtension iExt = (IssuingDistributionPointExtension) distExt; + IssuingDistributionPoint issuingDistributionPoint = null; + if(iExt != null) + issuingDistributionPoint = iExt.getIssuingDistributionPoint(); + if (value.equals(Constants.FALSE) && mCACertsOnly) { + clearCRLCache(); + updateCRLCacheRepository(); + mCACertsOnly = false; + } else if (value.equals(Constants.TRUE) && (!mCACertsOnly)) { + clearCRLCache(); + updateCRLCacheRepository(); + mCACertsOnly = true; + } + //attempt to sync the IssuingDistributionPoint Extension value of + //onlyContainsCACerts + if(issuingDistributionPoint != null && params.size() > 1) { + boolean onlyContainsCACerts = issuingDistributionPoint.getOnlyContainsCACerts(); + if(onlyContainsCACerts != mCACertsOnly) { + IConfigStore config = mCA.getConfigStore(); + IConfigStore crlsSubStore = + config.getSubStore(mCA.PROP_CRL_SUBSTORE); + IConfigStore crlSubStore = crlsSubStore.getSubStore(mId); + IConfigStore crlExtsSubStore = + crlSubStore.getSubStore(mCA.PROP_CRLEXT_SUBSTORE); + crlExtsSubStore = crlExtsSubStore.getSubStore(IssuingDistributionPointExtension.NAME); + + if(crlExtsSubStore != null) { + String val = ""; + if(mCACertsOnly == true) { + val = Constants.TRUE; + } else { + val = Constants.FALSE; + } + crlExtsSubStore.putString(PROP_CACERTS,val); + try { + crlExtsSubStore.commit(true); + } catch (Exception e) { + } + } + } + } + } + + if (name.equals(Constants.PR_PROFILE_CERTS_ONLY)) { + if (value.equals(Constants.FALSE) && mProfileCertsOnly) { + clearCRLCache(); + updateCRLCacheRepository(); + mProfileCertsOnly = false; + } else if (value.equals(Constants.TRUE) && (!mProfileCertsOnly)) { + clearCRLCache(); + updateCRLCacheRepository(); + mProfileCertsOnly = true; + } + } + + if (name.equals(Constants.PR_PROFILE_LIST)) { + Vector profileList = getProfileList(value); + if (((profileList != null) ^ (mProfileList != null)) || + (profileList != null && mProfileList != null && + (!mProfileList.equals(profileList)))) { + if (profileList != null) { + mProfileList = (Vector) profileList.clone(); + } else { + mProfileList = null; + } + clearCRLCache(); + updateCRLCacheRepository(); + } + if (mProfileList == null || mProfileList.isEmpty()) { + mProfileCertsOnly = false; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_INVALID_PROFILE_LIST")); + } + } + } + + if (modifiedSchedule) setAutoUpdates(); + + return noRestart; + } + } + + /** + * This method is called during shutdown. + *

+ */ + public synchronized void shutdown() { + // this should stop a thread if necessary + if (mEnableCRLCache && mCacheUpdateInterval > 0) { + updateCRLCacheRepository(); + } + mEnable = false; + + setAutoUpdates(); + /* + if (mUpdateThread != null) { + try { + mUpdateThread.interrupt(); + } + catch (Exception e) { + } + } + */ + } + + /** + * Returns internal id of this CRL issuing point. + *

+ * + * @return internal id of this CRL issuing point + */ + public String getId() { + return mId; + } + + /** + * Returns internal description of this CRL issuing point. + *

+ * + * @return internal description of this CRL issuing point + */ + public String getDescription() { + return mDescription; + } + + /** + * Sets internal description of this CRL issuing point. + * + * @param description description for this CRL issuing point. + */ + public void setDescription(String description) { + mDescription = description; + } + + /** + * Returns DN of the directory entry where CRLs.from this issuing point + * are published. + *

+ * + * @return DN of the directory entry where CRLs are published. + */ + public String getPublishDN() { + return mPublishDN; + } + + /** + * Returns signing algorithm. + *

+ * + * @return SigningAlgorithm. + */ + public String getSigningAlgorithm() { + return mSigningAlgorithm; + } + + public String getLastSigningAlgorithm() { + return mLastSigningAlgorithm; + } + + /** + * Returns current CRL generation schema for this CRL issuing point. + *

+ * + * @return current CRL generation schema for this CRL issuing point + */ + public int getCRLSchema() { + return mUpdateSchema; + } + + /** + * Returns current CRL number of this CRL issuing point. + *

+ * + * @return current CRL number of this CRL issuing point + */ + public BigInteger getCRLNumber() { + return mCRLNumber; + } + + /** + * Returns current delta CRL number of this CRL issuing point. + *

+ * + * @return current delta CRL number of this CRL issuing point + */ + public BigInteger getDeltaCRLNumber() { + return (isDeltaCRLEnabled() && mDeltaCRLSize > -1)? mDeltaCRLNumber: BigInteger.ZERO; + } + + /** + * Returns next CRL number of this CRL issuing point. + *

+ * + * @return next CRL number of this CRL issuing point + */ + public BigInteger getNextCRLNumber() { + return mNextDeltaCRLNumber; + } + + /** + * Returns number of entries in the CRL + *

+ * + * @return number of entries in the CRL + */ + public long getCRLSize() { + return (mCRLCerts.size() > 0 && mCRLSize == 0)? mCRLCerts.size(): mCRLSize; + } + + /** + * Returns number of entries in delta CRL + *

+ * + * @return number of entries in delta CRL + */ + public long getDeltaCRLSize() { + return mDeltaCRLSize; + } + + /** + * Returns last update time + *

+ * + * @return last CRL update time + */ + public Date getLastUpdate() { + return mLastUpdate; + } + + /** + * Returns next update time + *

+ * + * @return next CRL update time + */ + public Date getNextUpdate() { + return mNextUpdate; + } + + /** + * Returns next update time + *

+ * + * @return next CRL update time + */ + public Date getNextDeltaUpdate() { + return mNextDeltaUpdate; + } + + /** + * Returns all the revoked certificates from the CRL cache. + *

+ * + * @return set of all the revoked certificates or null if there are none. + */ + public Set getRevokedCertificates(int start, int end) { + if (mCRLCacheIsCleared || mCRLCerts == null || mCRLCerts.isEmpty()) { + return null; + } else { + ArraySet certSet = new ArraySet(); + Collection badCerts = mCRLCerts.values(); + Object[] objs = badCerts.toArray(); + for (int i = start; i < end && i < objs.length; i++) + certSet.add(objs[i]); + return certSet; + } + } + + /** + * Returns certificate authority. + *

+ * + * @return certificate authority + */ + public ISubsystem getCertificateAuthority() { + return mCA; + } + + /** + * Sets CRL auto updates + */ + + private synchronized void setAutoUpdates() { + if ((mEnable && mUpdateThread == null) && + ((mEnableCRLCache && mCacheUpdateInterval > 0) || + (mEnableCRLUpdates && + ((mEnableDailyUpdates && mDailyUpdates != null && + mTimeListSize > 0) || + (mEnableUpdateFreq && mAutoUpdateInterval > 0) || + (mInitialized == CRL_IP_NOT_INITIALIZED) || + mDoLastAutoUpdate || mDoManualUpdate)))) { + mUpdateThread = new Thread(this, "CRLIssuingPoint-" + mId); + log(ILogger.LL_INFO, CMS.getLogMessage("CMSCORE_CA_ISSUING_START_CRL", mId)); + mUpdateThread.setDaemon(true); + mUpdateThread.start(); + } + + if ((mInitialized == CRL_IP_INITIALIZED) && (((mNextUpdate != null) ^ + ((mEnableDailyUpdates && mDailyUpdates != null && mTimeListSize > 0) || + (mEnableUpdateFreq && mAutoUpdateInterval > 0))) || + (!mEnableCRLUpdates && mNextUpdate != null))) { + mDoLastAutoUpdate = true; + } + + if (mEnableUpdateFreq && mAutoUpdateInterval > 0 && + mAutoUpdateInterval < mMinUpdateInterval) { + mAutoUpdateInterval = mMinUpdateInterval; + } + + notifyAll(); + } + + /** + * Sets CRL manual-update + * Starts or stops worker thread as necessary. + */ + public synchronized void setManualUpdate(String signatureAlgorithm) { + if (!mDoManualUpdate) { + mDoManualUpdate = true; + mSignatureAlgorithmForManualUpdate = signatureAlgorithm; + if (mEnableUpdateFreq && mAutoUpdateInterval > 0 && mUpdateThread != null) { + notifyAll(); + } else { + setAutoUpdates(); + } + } + } + + /** + * @return auto update interval in milliseconds. + */ + public long getAutoUpdateInterval() { + return (mEnableUpdateFreq)? mAutoUpdateInterval: 0; + } + + /** + * @return always update the CRL + */ + public boolean getAlwaysUpdate() { + return mAlwaysUpdate; + } + + /** + * @return next update grace period in minutes. + */ + + public long getNextUpdateGracePeriod() { + return mNextUpdateGracePeriod; + } + + /** + * Finds next update time expressed as delay or time of the next update. + * + * @param fromLastUpdate if true, function returns delay to the next update time + * otherwise returns the next update time. + * @param delta if true, function returns the next update time for delta CRL, + * otherwise returns the next update time for CRL. + * @return delay to the next update time or the next update time itself + */ + private long findNextUpdate(boolean fromLastUpdate, boolean delta) { + long now = System.currentTimeMillis(); + TimeZone tz = TimeZone.getDefault(); + int offset = tz.getOffset(now); + long oneDay = 1440L * MINUTE; + long nowToday = (now + (long)offset) % oneDay; + long startOfToday = now - nowToday; + + long lastUpdated = (mLastUpdate != null)? mLastUpdate.getTime(): now; + long lastUpdateDay = lastUpdated - ((lastUpdated + (long)offset) % oneDay); + + long lastUpdate = (mLastUpdate != null && fromLastUpdate)? mLastUpdate.getTime(): now; + long last = (lastUpdate + (long)offset) % oneDay; + long lastDay = lastUpdate - last; + + boolean isDeltaEnabled = isDeltaCRLEnabled(); + long next = 0L; + long nextUpdate = 0L; + + CMS.debug("findNextUpdate: fromLastUpdate: "+fromLastUpdate+" delta: "+delta); + + int numberOfDays = (int)((startOfToday - lastUpdateDay) / oneDay); + if (numberOfDays > 0 && mDailyUpdates.size() > 1 && + ((mCurrentDay == mLastDay) || + (mCurrentDay != ((mLastDay + numberOfDays) % mDailyUpdates.size())))) { + mCurrentDay = (mLastDay + numberOfDays) % mDailyUpdates.size(); + } + + if ((delta || fromLastUpdate) && isDeltaEnabled && + (mUpdateSchema > 1 || (mEnableDailyUpdates && mExtendedTimeList)) && + mNextDeltaUpdate != null) { + nextUpdate = mNextDeltaUpdate.getTime(); + } else if (mNextUpdate != null) { + nextUpdate = mNextUpdate.getTime(); + } + + if (mEnableDailyUpdates && + mDailyUpdates != null && mDailyUpdates.size() > 0) { + int n = 0; + if (mDailyUpdates.size() == 1 && ((Vector)mDailyUpdates.elementAt(0)).size() == 1 && + mEnableUpdateFreq && mAutoUpdateInterval > 0) { + // Interval updates with starting time + long firstTime = MINUTE * ((Integer)((Vector)mDailyUpdates.elementAt(0)).elementAt(0)).longValue(); + long t = firstTime; + long interval = mAutoUpdateInterval; + if (mExtendedNextUpdate && (!fromLastUpdate) && (!delta) && + isDeltaEnabled && mUpdateSchema > 1) { + interval *= mUpdateSchema; + } + while (t < oneDay) { + if (t - mMinUpdateInterval > last) break; + t += interval; + n++; + } + + if (t <= oneDay) { + next = lastDay + t; + if (fromLastUpdate) { + n = n % mUpdateSchema; + if (t == firstTime) { + mSchemaCounter = 0; + } else if (n != mSchemaCounter) { + if (mSchemaCounter != 0 && (mSchemaCounter < n || n == 0)) { + mSchemaCounter = n; + } + } + } + } else { + next = lastDay + oneDay + firstTime; + if (fromLastUpdate) { + mSchemaCounter = 0; + } + } + } else { + // Daily updates following the list + if (last > nowToday) { + last = nowToday - 100; // 100ms - precision + } + int i, m; + for (i = 0, m = 0; i < mCurrentDay; i++) { + m += ((Vector)mDailyUpdates.elementAt(i)).size(); + } + // search the current day + for (i = 0; i < ((Vector)mDailyUpdates.elementAt(mCurrentDay)).size(); i++) { + long t = MINUTE * ((Integer)((Vector)mDailyUpdates.elementAt(mCurrentDay)).elementAt(i)).longValue(); + if (mEnableDailyUpdates && mExtendedTimeList) { + if (mExtendedNextUpdate && (!fromLastUpdate) && (!delta) && isDeltaEnabled) { + if (t < 0) { + t *= -1; + } else { + t = 0; + } + } else { + if (t < 0) { + t *= -1; + } + } + } + if (t - mMinUpdateInterval > last) { + if (mExtendedNextUpdate && (!fromLastUpdate) && (!(mEnableDailyUpdates && mExtendedTimeList)) && (!delta) && + isDeltaEnabled && mUpdateSchema > 1) { + i += mUpdateSchema - ((i + m) % mUpdateSchema); + } + break; + } + n++; + } + + if (i < ((Vector)mDailyUpdates.elementAt(mCurrentDay)).size()) { + // found inside the current day + next = (MINUTE * ((Integer)((Vector)mDailyUpdates.elementAt(mCurrentDay)).elementAt(i)).longValue()); + if (mEnableDailyUpdates && mExtendedTimeList && next < 0) { + next *= -1; + if (fromLastUpdate) { + mSchemaCounter = 0; + } + } + next += ((lastDay < lastUpdateDay)? lastDay: lastUpdateDay) + (oneDay * (mCurrentDay - mLastDay)); + + if (fromLastUpdate && (!(mEnableDailyUpdates && mExtendedTimeList))) { + n = n % mUpdateSchema; + if (i == 0 && mCurrentDay == 0) { + mSchemaCounter = 0; + } else if (n != mSchemaCounter) { + if (mSchemaCounter != 0 && ((n == 0 && mCurrentDay == 0) || mSchemaCounter < n)) { + mSchemaCounter = n; + } + } + } + } else { + // done with today + int j = i - ((Vector)mDailyUpdates.elementAt(mCurrentDay)).size(); + int nDays = 1; + long t = 0; + if (mDailyUpdates.size() > 1) { + while (nDays <= mDailyUpdates.size()) { + int nextDay = (mCurrentDay + nDays) % mDailyUpdates.size(); + if (j < ((Vector)mDailyUpdates.elementAt(nextDay)).size()) { + if (nextDay == 0 && (!(mEnableDailyUpdates && mExtendedTimeList))) j = 0; + t = MINUTE * ((Integer)((Vector)mDailyUpdates.elementAt(nextDay)).elementAt(j)).longValue(); + if (mEnableDailyUpdates && mExtendedTimeList) { + if (mExtendedNextUpdate && (!fromLastUpdate) && (!delta) && isDeltaEnabled) { + if (t < 0) { + t *= -1; + } else { + j++; + continue; + } + } else { + if (t < 0) { + t *= -1; + if (fromLastUpdate) { + mSchemaCounter = 0; + } + } + } + } + break; + } else { + j -= ((Vector)mDailyUpdates.elementAt(nextDay)).size(); + } + nDays++; + } + } + next = ((lastDay < lastUpdateDay)? lastDay: lastUpdateDay) + (oneDay * nDays) + t; + + if (fromLastUpdate && mDailyUpdates.size() < 2) { + mSchemaCounter = 0; + } + } + } + } else if (mEnableUpdateFreq && mAutoUpdateInterval > 0) { + // Interval updates without starting time + if (mExtendedNextUpdate && (!fromLastUpdate) && (!delta) && isDeltaEnabled && mUpdateSchema > 1) { + next = lastUpdate + (mUpdateSchema * mAutoUpdateInterval); + } else { + next = lastUpdate + mAutoUpdateInterval; + } + } + + if (fromLastUpdate && nextUpdate > 0 && (nextUpdate < next || nextUpdate >= now)) { + next = nextUpdate; + } + + CMS.debug("findNextUpdate: "+((new Date(next)).toString())+((fromLastUpdate)? " delay: "+(next-now): "")); + + return (fromLastUpdate)? next-now: next; + } + + + /** + * Implements Runnable interface. Defines auto-update + * logic used by worker thread. + *

+ */ + public void run() { + while (mEnable && ((mEnableCRLCache && mCacheUpdateInterval > 0) || + (mInitialized == CRL_IP_NOT_INITIALIZED) || + mDoLastAutoUpdate || (mEnableCRLUpdates && + ((mEnableDailyUpdates && mDailyUpdates != null && + mTimeListSize > 0) || + (mEnableUpdateFreq && mAutoUpdateInterval > 0) || + mDoManualUpdate)))) { + + synchronized (this) { + long delay = 0; + long delay2 = 0; + boolean doCacheUpdate = false; + boolean scheduledUpdates = mEnableCRLUpdates && + ((mEnableDailyUpdates && mDailyUpdates != null && + mTimeListSize > 0) || + (mEnableUpdateFreq && mAutoUpdateInterval > 0)); + + if (mInitialized == CRL_IP_NOT_INITIALIZED) + initCRL(); + if (mInitialized == CRL_IP_INITIALIZED && (!mEnable)) break; + + if ((mEnableCRLUpdates && mDoManualUpdate) || mDoLastAutoUpdate) { + delay = 0; + } else if (scheduledUpdates) { + delay = findNextUpdate(true, false); + } + + if (mEnableCRLCache && mCacheUpdateInterval > 0) { + delay2 = mLastCacheUpdate + mCacheUpdateInterval - + System.currentTimeMillis(); + if (delay2 < delay || + (!(scheduledUpdates || mDoLastAutoUpdate || + (mEnableCRLUpdates && mDoManualUpdate)))) { + delay = delay2; + if (delay <= 0) { + doCacheUpdate = true; + mLastCacheUpdate = System.currentTimeMillis(); + } + } + } + + if (delay > 0) { + try { + wait(delay); + } catch (InterruptedException e) { + } + } else { + try { + if (doCacheUpdate) { + updateCRLCacheRepository(); + } else if (mAutoUpdateInterval > 0 || mDoLastAutoUpdate || mDoManualUpdate) { + updateCRL(); + } + } catch (Exception e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_CRL", + (doCacheUpdate)?"update CRL cache":"update CRL", e.toString())); + if (Debug.on()) { + Debug.trace((doCacheUpdate)?"update CRL cache":"update CRL" + " error " + e); + Debug.printStackTrace(e); + } + } + // put this here to prevent continuous loop if internal + // db is down. + if (mDoLastAutoUpdate) + mDoLastAutoUpdate = false; + if (mDoManualUpdate) { + mDoManualUpdate = false; + mSignatureAlgorithmForManualUpdate = null; + } + } + } + } + mUpdateThread = null; + } + + + /** + * Updates CRL and publishes it. + * If time elapsed since last CRL update is less than + * minUpdateInterval silently returns. + * Otherwise determines nextUpdate by adding autoUpdateInterval or + * minUpdateInterval to the current time. If neither of the + * intervals are defined nextUpdate will be null. + * Then using specified configuration parameters it formulates new + * CRL, signs it, updates CRLIssuingPointRecord in the database + * and publishes CRL in the directory. + *

+ */ + private void updateCRL() throws EBaseException { + /* + if (mEnableUpdateFreq && mAutoUpdateInterval > 0 && + (System.currentTimeMillis() - mLastUpdate.getTime() < + mMinUpdateInterval)) { + // log or alternatively throw an Exception + return; + } + */ + if (mDoManualUpdate && mSignatureAlgorithmForManualUpdate != null) { + updateCRLNow(mSignatureAlgorithmForManualUpdate); + } else { + updateCRLNow(); + } + } + + /** + * This method may be overrided by CRLWithExpiredCerts.java + */ + public String getFilter() { + // PLEASE DONT CHANGE THE FILTER. It is indexed. + // Changing it will degrade performance. See + // also com.netscape.certsetup.LDAPUtil.java + String filter = ""; + + if (mIncludeExpiredCerts) + filter += "(|"; + filter += "(" + CertRecord.ATTR_CERT_STATUS + "=" + CertRecord.STATUS_REVOKED + ")"; + if (mIncludeExpiredCerts) + filter += "(" + CertRecord.ATTR_CERT_STATUS + "=" + CertRecord.STATUS_REVOKED_EXPIRED + "))"; + + if (mCACertsOnly) { + filter += "(x509cert.BasicConstraints.isCA=on)"; + } + + if (mProfileCertsOnly && mProfileList != null && mProfileList.size() > 0) { + if (mProfileList.size() > 1) { + filter += "(|"; + } + for (int k = 0; k < mProfileList.size(); k++) { + String id = (String) mProfileList.elementAt(k); + filter += "(" + CertRecord.ATTR_META_INFO + "=profileId:" + id + ")"; + } + if (mProfileList.size() > 1) { + filter += ")"; + } + } + + // check if any ranges specified. + if (mBeginSerial != null) { + filter += "(" + CertRecord.ATTR_ID + ">=" + mBeginSerial.toString() + ")"; + } + if (mEndSerial != null) { + filter += "(" + CertRecord.ATTR_ID + "<=" + mEndSerial.toString() + ")"; + } + + // get all revoked non-expired certs. + if (mEndSerial != null || mBeginSerial != null || mCACertsOnly || + (mProfileCertsOnly && mProfileList != null && mProfileList.size() > 0)) { + filter = "(&" + filter + ")"; + } + + return filter; + } + + /** + * Gets a enumeration of revoked certs to put into CRL. + * This does not include expired certs. + * Override this method to make a CRL other than the + * full/complete CRL. + * @return Enumeration of CertRecords to put into CRL. + * @exception EBaseException if an error occured in the database. + */ + public void processRevokedCerts(IElementProcessor p) + throws EBaseException { + CertRecProcessor cp = (CertRecProcessor) p; + String filter = getFilter(); + + // NOTE: dangerous cast. + // correct way would be to modify interface and add + // accessor but we don't want to touch the interface + CertificateRepository cr = (CertificateRepository)mCertRepository; + + synchronized (cr.mCertStatusUpdateThread) { + CMS.debug("Starting processRevokedCerts (entered lock)"); + ICertRecordList list = mCertRepository.findCertRecordsInList(filter, + new String[] {ICertRecord.ATTR_ID, ICertRecord.ATTR_REVO_INFO, "objectclass" }, + "serialno", + mPageSize); + + int totalSize = list.getSize(); + + list.processCertRecords(0, totalSize - 1, cp); + CMS.debug("processRevokedCerts done"); + } + } + + /** + * clears CRL cache + */ + public void clearCRLCache() { + mCRLCacheIsCleared = true; + mCRLCerts.clear(); + mRevokedCerts.clear(); + mUnrevokedCerts.clear(); + mExpiredCerts.clear(); + mSchemaCounter = 0; + } + + /** + * clears Delta-CRL cache + */ + public void clearDeltaCRLCache() { + mRevokedCerts.clear(); + mUnrevokedCerts.clear(); + mExpiredCerts.clear(); + mSchemaCounter = 0; + } + + /** + * recovers CRL cache + */ + private void recoverCRLCache() { + if (mEnableCacheRecovery) { + // 553815 - original filter was not aligned with any VLV index + // String filter = "(&(requeststate=complete)"+ + // "(|(requestType=" + IRequest.REVOCATION_REQUEST + ")"+ + // "(requestType=" + IRequest.UNREVOCATION_REQUEST + ")))"; + String filter = "(requeststate=complete)"; + if (Debug.on()) { + Debug.trace("recoverCRLCache mFirstUnsaved="+mFirstUnsaved+" filter="+filter); + } + IRequestQueue mQueue = mCA.getRequestQueue(); + + IRequestVirtualList list = mQueue.getPagedRequestsByFilter( + new RequestId(mFirstUnsaved), filter, 500, "requestId"); + if (Debug.on()) { + Debug.trace("recoverCRLCache size="+list.getSize()+" index="+list.getCurrentIndex()); + } + + CertRecProcessor cp = new CertRecProcessor(mCRLCerts, this, mLogger, mAllowExtensions); + boolean includeCert = true; + + int s = list.getSize() - list.getCurrentIndex(); + for (int i = 0; i < s; i++) { + IRequest request = null; + try { + request = list.getElementAt(i); + } catch (Exception e) { + // handled below + } + if (request == null) { + continue; + } + if (Debug.on()) { + Debug.trace("recoverCRLCache request="+request.getRequestId().toString()+ + " type="+request.getRequestType()); + } + if (IRequest.REVOCATION_REQUEST.equals(request.getRequestType())) { + RevokedCertImpl revokedCert[] = + request.getExtDataInRevokedCertArray(IRequest.CERT_INFO); + for (int j = 0; j < revokedCert.length; j++) { + if (Debug.on()) { + Debug.trace("recoverCRLCache R j="+j+" length="+revokedCert.length+ + " SerialNumber=0x"+revokedCert[j].getSerialNumber().toString(16)); + } + if(cp != null) + includeCert = cp.checkRevokedCertExtensions(revokedCert[j].getExtensions()); + if(includeCert) { + updateRevokedCert(REVOKED_CERT, revokedCert[j].getSerialNumber(), revokedCert[j]); + } + } + } else if (IRequest.UNREVOCATION_REQUEST.equals(request.getRequestType())) { + BigInteger serialNo[] = request.getExtDataInBigIntegerArray(IRequest.OLD_SERIALS); + for (int j = 0; j < serialNo.length; j++) { + if (Debug.on()) { + Debug.trace("recoverCRLCache U j="+j+" length="+serialNo.length+ + " SerialNumber=0x"+serialNo[j].toString(16)); + } + updateRevokedCert(UNREVOKED_CERT, serialNo[j], null); + } + } + } + + try { + mCRLRepository.updateRevokedCerts(mId, mRevokedCerts, mUnrevokedCerts); + mFirstUnsaved = ICRLIssuingPointRecord.CLEAN_CACHE; + mCRLCacheIsCleared = false; + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_STORE_CRL_CACHE", e.toString())); + } + } else { + clearCRLCache(); + updateCRLCacheRepository(); + } + } + + public int getNumberOfRecentlyRevokedCerts() { + return mRevokedCerts.size(); + } + + public int getNumberOfRecentlyUnrevokedCerts() { + return mUnrevokedCerts.size(); + } + + public int getNumberOfRecentlyExpiredCerts() { + return mExpiredCerts.size(); + } + + private Extension getCRLExtension(String extName) { + if(mAllowExtensions == false) { + return null; + } + if(mCMSCRLExtensions.isCRLExtensionEnabled(extName) == false) { + return null; + } + + CMSCRLExtensions exts = (CMSCRLExtensions) this.getCRLExtensions(); + CRLExtensions ext = new CRLExtensions(); + + Vector extNames = exts.getCRLExtensionNames(); + for (int i = 0; i < extNames.size(); i++) { + String curName = (String) extNames.elementAt(i); + if (curName.equals(extName)) { + exts.addToCRLExtensions(ext, extName, null); + } + } + Extension theExt = null; + try { + theExt = ext.get(extName); + } catch (Exception e) { + } + + CMS.debug("CRLIssuingPoint.getCRLExtension extension: " + theExt); + return theExt; + } + /** + * get required crl entry extensions + */ + public CRLExtensions getRequiredEntryExtensions(CRLExtensions exts) { + CRLExtensions entryExt = null; + + if (mAllowExtensions && exts != null && exts.size() > 0) { + entryExt = new CRLExtensions(); + Vector extNames = mCMSCRLExtensions.getCRLEntryExtensionNames(); + + for (int i = 0; i < extNames.size(); i++) { + String extName = (String) extNames.elementAt(i); + + if (mCMSCRLExtensions.isCRLExtensionEnabled(extName)) { + int k; + + for (k = 0; k < exts.size(); k++) { + Extension ext = (Extension) exts.elementAt(k); + String name = mCMSCRLExtensions.getCRLExtensionName( + ext.getExtensionId().toString()); + + if (extName.equals(name)) { + if (!(ext instanceof CRLReasonExtension) || + (((CRLReasonExtension) ext).getReason().toInt() > + RevocationReason.UNSPECIFIED.toInt())) { + mCMSCRLExtensions.addToCRLExtensions(entryExt, extName, ext); + } + break; + } + } + if (k == exts.size()) { + mCMSCRLExtensions.addToCRLExtensions(entryExt, extName, null); + } + } + } + } + + return entryExt; + } + + private static final int REVOKED_CERT = 1; + private static final int UNREVOKED_CERT = 2; + private Object cacheMonitor = new Object(); + + /** + * update CRL cache with new revoked-unrevoked certificate info + */ + private void updateRevokedCert(int certType, + BigInteger serialNumber, + RevokedCertImpl revokedCert) { + updateRevokedCert(certType, serialNumber, revokedCert, null); + } + + private void updateRevokedCert(int certType, + BigInteger serialNumber, + RevokedCertImpl revokedCert, + String requestId) { + synchronized (cacheMonitor) { + if (requestId != null && mFirstUnsaved != null && + mFirstUnsaved.equals(ICRLIssuingPointRecord.CLEAN_CACHE)) { + mFirstUnsaved = requestId; + try { + mCRLRepository.updateFirstUnsaved(mId, mFirstUnsaved); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_STORE_CRL_CACHE", e.toString())); + } + } + if (certType == REVOKED_CERT) { + if (mUnrevokedCerts.containsKey(serialNumber)) { + mUnrevokedCerts.remove(serialNumber); + if (mCRLCerts.containsKey(serialNumber)) { + Date revocationDate = revokedCert.getRevocationDate(); + CRLExtensions entryExt = getRequiredEntryExtensions(revokedCert.getExtensions()); + RevokedCertImpl newRevokedCert = + new RevokedCertImpl(serialNumber, revocationDate, entryExt); + + mCRLCerts.put(serialNumber, (RevokedCertificate) newRevokedCert); + } + } else { + Date revocationDate = revokedCert.getRevocationDate(); + CRLExtensions entryExt = getRequiredEntryExtensions(revokedCert.getExtensions()); + RevokedCertImpl newRevokedCert = + new RevokedCertImpl(serialNumber, revocationDate, entryExt); + + mRevokedCerts.put(serialNumber, (RevokedCertificate) newRevokedCert); + } + } else if (certType == UNREVOKED_CERT) { + if (mRevokedCerts.containsKey(serialNumber)) { + mRevokedCerts.remove(serialNumber); + } else { + CRLExtensions entryExt = new CRLExtensions(); + + try { + entryExt.set(CRLReasonExtension.REMOVE_FROM_CRL.getName(), + CRLReasonExtension.REMOVE_FROM_CRL); + } catch (IOException e) { + } + RevokedCertImpl newRevokedCert = new RevokedCertImpl(serialNumber, + CMS.getCurrentDate(), entryExt); + + mUnrevokedCerts.put(serialNumber, (RevokedCertificate) newRevokedCert); + } + } + } + } + + /** + * registers revoked certificates + */ + public void addRevokedCert(BigInteger serialNumber, RevokedCertImpl revokedCert) { + addRevokedCert(serialNumber, revokedCert, null); + } + + public void addRevokedCert(BigInteger serialNumber, RevokedCertImpl revokedCert, + String requestId) { + + CertRecProcessor cp = new CertRecProcessor(mCRLCerts, this, mLogger, mAllowExtensions); + boolean includeCert = true; + if(cp != null) + includeCert = cp.checkRevokedCertExtensions(revokedCert.getExtensions()); + + if (mEnable && mEnableCRLCache && includeCert == true) { + updateRevokedCert(REVOKED_CERT, serialNumber, revokedCert, requestId); + + if (mCacheUpdateInterval == 0) { + try { + mCRLRepository.updateRevokedCerts(mId, mRevokedCerts, mUnrevokedCerts); + mFirstUnsaved = ICRLIssuingPointRecord.CLEAN_CACHE; + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_STORE_REVOKED_CERT", mId, e.toString())); + } + } + } + } + + /** + * registers unrevoked certificates + */ + public void addUnrevokedCert(BigInteger serialNumber) { + addUnrevokedCert(serialNumber, null); + } + + public void addUnrevokedCert(BigInteger serialNumber, String requestId) { + if (mEnable && mEnableCRLCache) { + updateRevokedCert(UNREVOKED_CERT, serialNumber, null, requestId); + + if (mCacheUpdateInterval == 0) { + try { + mCRLRepository.updateRevokedCerts(mId, mRevokedCerts, mUnrevokedCerts); + mFirstUnsaved = ICRLIssuingPointRecord.CLEAN_CACHE; + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_STORE_UNREVOKED_CERT", mId, e.toString())); + } + } + } + } + + /** + * registers expired certificates + */ + public void addExpiredCert(BigInteger serialNumber) { + + if (mEnable && mEnableCRLCache && (!mIncludeExpiredCerts)) { + if (!(mExpiredCerts.containsKey(serialNumber))) { + CRLExtensions entryExt = new CRLExtensions(); + + try { + entryExt.set(CRLReasonExtension.REMOVE_FROM_CRL.getName(), + CRLReasonExtension.REMOVE_FROM_CRL); + } catch (IOException e) { + } + RevokedCertImpl newRevokedCert = new RevokedCertImpl(serialNumber, + CMS.getCurrentDate(), entryExt); + + mExpiredCerts.put(serialNumber, (RevokedCertificate) newRevokedCert); + } + + if (mCacheUpdateInterval == 0) { + try { + mCRLRepository.updateExpiredCerts(mId, mExpiredCerts); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_STORE_EXPIRED_CERT", mId, e.toString())); + } + } + } + } + + private Object repositoryMonitor = new Object(); + + public void updateCRLCacheRepository() { + synchronized (repositoryMonitor) { + try { + mCRLRepository.updateCRLCache(mId, Long.valueOf(mCRLSize), + mRevokedCerts, mUnrevokedCerts, mExpiredCerts); + mFirstUnsaved = ICRLIssuingPointRecord.CLEAN_CACHE; + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_STORE_CRL_CACHE", e.toString())); + } + } + } + + public boolean isDeltaCRLEnabled() { + return (mAllowExtensions && mEnableCRLCache && + mCMSCRLExtensions.isCRLExtensionEnabled(DeltaCRLIndicatorExtension.NAME) && + mCMSCRLExtensions.isCRLExtensionEnabled(CRLNumberExtension.NAME) && + mCMSCRLExtensions.isCRLExtensionEnabled(CRLReasonExtension.NAME)); + } + + public boolean isThisCurrentDeltaCRL(X509CRLImpl deltaCRL) { + boolean result = false; + + if (isDeltaCRLEnabled() && mDeltaCRLSize > -1) { + if (deltaCRL != null) { + CRLExtensions crlExtensions = deltaCRL.getExtensions(); + + if (crlExtensions != null) { + for (int k = 0; k < crlExtensions.size(); k++) { + Extension ext = (Extension) crlExtensions.elementAt(k); + + if (DeltaCRLIndicatorExtension.OID.equals(ext.getExtensionId().toString())) { + DeltaCRLIndicatorExtension dExt = (DeltaCRLIndicatorExtension) ext; + BigInteger crlNumber = null; + + try { + crlNumber = (BigInteger) dExt.get(DeltaCRLIndicatorExtension.NUMBER); + } catch (IOException e) { + } + if (crlNumber != null && (crlNumber.equals(mLastCRLNumber) || + mLastCRLNumber.equals(BigInteger.ZERO))) { + result = true; + } + } + } + } + } + } + return (result); + } + + public boolean isCRLCacheEnabled() { + return mEnableCRLCache; + } + + public boolean isCRLCacheEmpty() { + return ((mCRLCerts != null)? mCRLCerts.isEmpty(): true); + } + + public boolean isCRLCacheTestingEnabled() { + return mEnableCacheTesting; + } + + public Date getRevocationDateFromCache(BigInteger serialNumber, + boolean checkDeltaCache, + boolean includeExpiredCerts) { + Date revocationDate = null; + + if (mCRLCerts.containsKey(serialNumber)) { + revocationDate = ((RevokedCertificate) mCRLCerts.get(serialNumber)).getRevocationDate(); + } + + if (checkDeltaCache && isDeltaCRLEnabled()) { + if (mUnrevokedCerts.containsKey(serialNumber)) { + revocationDate = null; + } + if (mRevokedCerts.containsKey(serialNumber)) { + revocationDate = ((RevokedCertificate) mRevokedCerts.get(serialNumber)).getRevocationDate(); + } + if (!includeExpiredCerts && mExpiredCerts.containsKey(serialNumber)) { + revocationDate = null; + } + } + + return revocationDate; + } + + public Vector getSplitTimes() { + Vector splits = new Vector(); + + for (int i = 0; i < mSplits.length; i++) { + splits.addElement(Long.valueOf(mSplits[i])); + } + return splits; + } + + public int isCRLUpdateInProgress() { + return mUpdatingCRL; + } + + /** + * updates CRL and publishes it now + */ + public void updateCRLNow() + throws EBaseException { + + updateCRLNow(null); + } + + public synchronized void updateCRLNow(String signingAlgorithm) + throws EBaseException { + + if ((!mEnable) || (!mEnableCRLUpdates && !mDoLastAutoUpdate)) return; + CMS.debug("Updating CRL"); + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, AuditFormat.LEVEL, + CMS.getLogMessage("CMSCORE_CA_CA_CRL_UPDATE_STARTED"), + new Object[] { + getId(), + getNextCRLNumber(), + Boolean.toString(isDeltaCRLEnabled()), + Boolean.toString(isCRLCacheEnabled()), + Boolean.toString(mEnableCacheRecovery), + Boolean.toString(mCRLCacheIsCleared), + ""+mCRLCerts.size()+","+mRevokedCerts.size()+","+mUnrevokedCerts.size()+","+mExpiredCerts.size()+"" + } + ); + mUpdatingCRL = CRL_UPDATE_STARTED; + if (signingAlgorithm == null || signingAlgorithm.length() == 0) + signingAlgorithm = mSigningAlgorithm; + mLastSigningAlgorithm = signingAlgorithm; + Date thisUpdate = CMS.getCurrentDate(); + Date nextUpdate = null; + Date nextDeltaUpdate = null; + + if (mEnableCRLUpdates && ((mEnableDailyUpdates && + mDailyUpdates != null && mTimeListSize > 0) || + (mEnableUpdateFreq && mAutoUpdateInterval > 0))) { + + if ((!isDeltaCRLEnabled()) || mSchemaCounter == 0 || mUpdateSchema == 1) { + nextUpdate = new Date(findNextUpdate(false, false)); + mNextUpdate = new Date(nextUpdate.getTime()); + } + if (isDeltaCRLEnabled()) { + if (mUpdateSchema > 1 || (mEnableDailyUpdates && mExtendedTimeList && mTimeListSize > 1)) { + nextDeltaUpdate = new Date(findNextUpdate(false, true)); + if (mExtendedNextUpdate && mSchemaCounter > 0 && + mNextUpdate != null && mNextUpdate.equals(nextDeltaUpdate)) { + if (mEnableDailyUpdates && mExtendedTimeList && mTimeListSize > 1) { + mSchemaCounter = mTimeListSize - 1; + } else { + mSchemaCounter = mUpdateSchema - 1; + } + } + } else { + nextDeltaUpdate = new Date(nextUpdate.getTime()); + if (mUpdateSchema == 1) { + mSchemaCounter = 0; + } + } + } + } + + for (int i = 0; i < mSplits.length; i++) { + mSplits[i] = 0; + } + + mLastUpdate = thisUpdate; + // mNextUpdate = nextUpdate; + mNextDeltaUpdate = (nextDeltaUpdate != null)? new Date(nextDeltaUpdate.getTime()): null; + if (nextUpdate != null) { + nextUpdate.setTime((nextUpdate.getTime())+mNextUpdateGracePeriod); + } + if (nextDeltaUpdate != null) { + nextDeltaUpdate.setTime((nextDeltaUpdate.getTime())+mNextUpdateGracePeriod); + } + + mSplits[0] -= System.currentTimeMillis(); + Hashtable clonedRevokedCerts = (Hashtable) mRevokedCerts.clone(); + Hashtable clonedUnrevokedCerts = (Hashtable) mUnrevokedCerts.clone(); + Hashtable clonedExpiredCerts = (Hashtable) mExpiredCerts.clone(); + + mSplits[0] += System.currentTimeMillis(); + + // starting from the beginning + + if ((!mEnableCRLCache) || + ((mCRLCacheIsCleared && mCRLCerts.isEmpty() && clonedRevokedCerts.isEmpty() && + clonedUnrevokedCerts.isEmpty() && clonedExpiredCerts.isEmpty()) || + (mCRLCerts.isEmpty() && (!clonedUnrevokedCerts.isEmpty())) || + (mCRLCerts.size() < clonedUnrevokedCerts.size()) || + (mCRLCerts.isEmpty() && (mCRLSize > 0)) || + (mCRLCerts.size() > 0 && mCRLSize == 0))) { + + mSplits[5] -= System.currentTimeMillis(); + mDeltaCRLSize = -1; + clearCRLCache(); + clonedRevokedCerts.clear(); + clonedUnrevokedCerts.clear(); + clonedExpiredCerts.clear(); + mSchemaCounter = 0; + + IStatsSubsystem statsSub = (IStatsSubsystem)CMS.getSubsystem("stats"); + if (statsSub != null) { + statsSub.startTiming("generation"); + } + CertRecProcessor cp = new CertRecProcessor(mCRLCerts, this, mLogger, mAllowExtensions); + processRevokedCerts(cp); + + if (statsSub != null) { + statsSub.endTiming("generation"); + } + + mCRLCacheIsCleared = false; + mSplits[5] += System.currentTimeMillis(); + } else { + if (isDeltaCRLEnabled()) { + mSplits[1] -= System.currentTimeMillis(); + Hashtable deltaCRLCerts = (Hashtable) clonedRevokedCerts.clone(); + + deltaCRLCerts.putAll(clonedUnrevokedCerts); + if (mIncludeExpiredCertsOneExtraTime) { + if (!clonedExpiredCerts.isEmpty()) { + for (Enumeration e = clonedExpiredCerts.keys(); e.hasMoreElements();) { + BigInteger serialNumber = (BigInteger) e.nextElement(); + if ((mLastFullUpdate != null && + mLastFullUpdate.after(((RevokedCertificate)(mExpiredCerts.get(serialNumber))).getRevocationDate())) || + mLastFullUpdate == null) { + deltaCRLCerts.put(serialNumber, clonedExpiredCerts.get(serialNumber)); + } + } + } + } else { + deltaCRLCerts.putAll(clonedExpiredCerts); + } + + mLastCRLNumber = mCRLNumber; + + CRLExtensions ext = new CRLExtensions(); + Vector extNames = mCMSCRLExtensions.getCRLExtensionNames(); + + for (int i = 0; i < extNames.size(); i++) { + String extName = (String) extNames.elementAt(i); + + if (mCMSCRLExtensions.isCRLExtensionEnabled(extName) && + (!extName.equals(FreshestCRLExtension.NAME))) { + mCMSCRLExtensions.addToCRLExtensions(ext, extName, null); + } + } + mSplits[1] += System.currentTimeMillis(); + + X509CRLImpl newX509DeltaCRL = null; + + try { + mSplits[2] -= System.currentTimeMillis(); + byte[] newDeltaCRL; + + // #56123 - dont generate CRL if no revoked certificates + if (mConfigStore.getBoolean("noCRLIfNoRevokedCert", false)) { + if (deltaCRLCerts.size() == 0) { + CMS.debug("CRLIssuingPoint: No Revoked Certificates Found And noCRLIfNoRevokedCert is set to true - No Delta CRL Generated"); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", "No Revoked Certificates")); + } + } + X509CRLImpl crl = new X509CRLImpl(mCA.getCRLX500Name(), + AlgorithmId.get(signingAlgorithm), + thisUpdate, nextDeltaUpdate, deltaCRLCerts, ext); + + newX509DeltaCRL = mCA.sign(crl, signingAlgorithm); + newDeltaCRL = newX509DeltaCRL.getEncoded(); + mSplits[2] += System.currentTimeMillis(); + + mSplits[3] -= System.currentTimeMillis(); + mCRLRepository.updateDeltaCRL(mId, mNextDeltaCRLNumber, + Long.valueOf(deltaCRLCerts.size()), mNextDeltaUpdate, newDeltaCRL); + mSplits[3] += System.currentTimeMillis(); + + mDeltaCRLSize = deltaCRLCerts.size(); + + + long totalTime = 0; + String splitTimes = " ("; + for (int i = 1; i < mSplits.length && i < 5; i++) { + totalTime += mSplits[i]; + if (i > 1) splitTimes += ","; + splitTimes += Long.toString(mSplits[i]); + } + splitTimes += ")"; + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + CMS.getLogMessage("CMSCORE_CA_CA_DELTA_CRL_UPDATED"), + new Object[] { + getId(), + getNextCRLNumber(), + getCRLNumber(), + getLastUpdate(), + getNextDeltaUpdate(), + Long.toString(mDeltaCRLSize), + Long.toString(totalTime)+splitTimes + } + ); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_SIGN_OR_STORE_DELTA", e.toString())); + mDeltaCRLSize = -1; + } catch (NoSuchAlgorithmException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_SIGN_DELTA", e.toString())); + mDeltaCRLSize = -1; + } catch (CRLException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_SIGN_DELTA", e.toString())); + mDeltaCRLSize = -1; + } catch (X509ExtensionException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_SIGN_DELTA", e.toString())); + mDeltaCRLSize = -1; + } catch (OutOfMemoryError e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_SIGN_DELTA", e.toString())); + mDeltaCRLSize = -1; + } + + try { + mSplits[4] -= System.currentTimeMillis(); + publishCRL(newX509DeltaCRL, true); + mSplits[4] += System.currentTimeMillis(); + } catch (EBaseException e) { + newX509DeltaCRL = null; + if (Debug.on()) + Debug.printStackTrace(e); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_PUBLISH_DELTA", mCRLNumber.toString(), e.toString())); + } catch (OutOfMemoryError e) { + newX509DeltaCRL = null; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_PUBLISH_DELTA", mCRLNumber.toString(), e.toString())); + } + } else { + mDeltaCRLSize = -1; + } + + mSplits[5] -= System.currentTimeMillis(); + + if (mSchemaCounter == 0) { + if (((!mCRLCerts.isEmpty()) && ((!clonedRevokedCerts.isEmpty()) || + (!clonedUnrevokedCerts.isEmpty()) || (!clonedExpiredCerts.isEmpty()))) || + (mCRLCerts.isEmpty() && (mCRLSize == 0) && (!clonedRevokedCerts.isEmpty()))) { + + if (!clonedUnrevokedCerts.isEmpty()) { + for (Enumeration e = clonedUnrevokedCerts.keys(); e.hasMoreElements();) { + BigInteger serialNumber = (BigInteger) e.nextElement(); + + if (mCRLCerts.containsKey(serialNumber)) { + mCRLCerts.remove(serialNumber); + } + mUnrevokedCerts.remove(serialNumber); + } + } + + if (!clonedRevokedCerts.isEmpty()) { + for (Enumeration e = clonedRevokedCerts.keys(); e.hasMoreElements();) { + BigInteger serialNumber = (BigInteger) e.nextElement(); + + mCRLCerts.put(serialNumber, mRevokedCerts.get(serialNumber)); + mRevokedCerts.remove(serialNumber); + } + } + + if (!clonedExpiredCerts.isEmpty()) { + for (Enumeration e = clonedExpiredCerts.keys(); e.hasMoreElements();) { + BigInteger serialNumber = (BigInteger) e.nextElement(); + + if ((!mIncludeExpiredCertsOneExtraTime) || + (mLastFullUpdate != null && + mLastFullUpdate.after(((RevokedCertificate)(mExpiredCerts.get(serialNumber))).getRevocationDate())) || + mLastFullUpdate == null) { + if (mCRLCerts.containsKey(serialNumber)) { + mCRLCerts.remove(serialNumber); + } + mExpiredCerts.remove(serialNumber); + } + } + } + } + mLastFullUpdate = mLastUpdate; + } + mSplits[5] += System.currentTimeMillis(); + } + + clonedRevokedCerts.clear(); + clonedUnrevokedCerts.clear(); + clonedExpiredCerts.clear(); + clonedRevokedCerts = null; + clonedUnrevokedCerts = null; + clonedExpiredCerts = null; + + if ((!isDeltaCRLEnabled()) || mSchemaCounter == 0) { + mSplits[6] -= System.currentTimeMillis(); + if (mNextDeltaCRLNumber.compareTo(mNextCRLNumber) > 0) { + mNextCRLNumber = mNextDeltaCRLNumber; + } + + CRLExtensions ext = null; + + if (mAllowExtensions) { + ext = new CRLExtensions(); + Vector extNames = mCMSCRLExtensions.getCRLExtensionNames(); + + for (int i = 0; i < extNames.size(); i++) { + String extName = (String) extNames.elementAt(i); + + if (mCMSCRLExtensions.isCRLExtensionEnabled(extName) && + (!extName.equals(DeltaCRLIndicatorExtension.NAME))) { + mCMSCRLExtensions.addToCRLExtensions(ext, extName, null); + } + } + } + mSplits[6] += System.currentTimeMillis(); + // for audit log + + X509CRLImpl newX509CRL; + + try { + byte[] newCRL; + + CMS.debug("Making CRL with algorithm " + + signingAlgorithm + " " + AlgorithmId.get(signingAlgorithm)); + + mSplits[7] -= System.currentTimeMillis(); + + // #56123 - dont generate CRL if no revoked certificates + if (mConfigStore.getBoolean("noCRLIfNoRevokedCert", false)) { + if (mCRLCerts.size() == 0) { + CMS.debug("CRLIssuingPoint: No Revoked Certificates Found And noCRLIfNoRevokedCert is set to true - No CRL Generated"); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", "No Revoked Certificates")); + } + } + CMS.debug("before new X509CRLImpl"); + X509CRLImpl crl = new X509CRLImpl(mCA.getCRLX500Name(), + AlgorithmId.get(signingAlgorithm), + thisUpdate, nextUpdate, mCRLCerts, ext); + + CMS.debug("before sign"); + newX509CRL = mCA.sign(crl, signingAlgorithm); + + CMS.debug("before getEncoded()"); + newCRL = newX509CRL.getEncoded(); + CMS.debug("after getEncoded()"); + mSplits[7] += System.currentTimeMillis(); + + mSplits[8] -= System.currentTimeMillis(); + + Date nextUpdateDate = mNextUpdate; + if (isDeltaCRLEnabled() && (mUpdateSchema > 1 || + (mEnableDailyUpdates && mExtendedTimeList)) && mNextDeltaUpdate != null) { + nextUpdateDate = mNextDeltaUpdate; + } + if (mSaveMemory) { + mCRLRepository.updateCRLIssuingPointRecord( + mId, newCRL, thisUpdate, nextUpdateDate, + mNextCRLNumber, Long.valueOf(mCRLCerts.size())); + updateCRLCacheRepository(); + } else { + mCRLRepository.updateCRLIssuingPointRecord( + mId, newCRL, thisUpdate, nextUpdateDate, + mNextCRLNumber, Long.valueOf(mCRLCerts.size()), + mRevokedCerts, mUnrevokedCerts, mExpiredCerts); + mFirstUnsaved = ICRLIssuingPointRecord.CLEAN_CACHE; + } + + mSplits[8] += System.currentTimeMillis(); + + mCRLSize = mCRLCerts.size(); + mCRLNumber = mNextCRLNumber; + mDeltaCRLNumber = mCRLNumber; + mNextCRLNumber = mCRLNumber.add(BigInteger.ONE); + mNextDeltaCRLNumber = mNextCRLNumber; + + + CMS.debug("Logging CRL Update to transaction log"); + long totalTime = 0; + long crlTime = 0; + long deltaTime = 0; + String splitTimes = " ("; + for (int i = 0; i < mSplits.length; i++) { + totalTime += mSplits[i]; + if (i > 0 && i < 5) { + deltaTime += mSplits[i]; + } else { + crlTime += mSplits[i]; + } + if (i > 0) splitTimes += ","; + splitTimes += Long.toString(mSplits[i]); + } + splitTimes += "," + Long.toString(deltaTime) + "," + Long.toString(crlTime) + "," + Long.toString(totalTime) + ")"; + mLogger.log(ILogger.EV_AUDIT, ILogger.S_OTHER, + AuditFormat.LEVEL, + CMS.getLogMessage("CMSCORE_CA_CA_CRL_UPDATED"), + new Object[] { + getId(), + getCRLNumber(), + getLastUpdate(), + getNextUpdate(), + Long.toString(mCRLSize), + Long.toString(totalTime), + Long.toString(crlTime), + Long.toString(deltaTime)+splitTimes + } + ); + CMS.debug("Finished Logging CRL Update to transaction log"); + + } catch (EBaseException e) { + newX509CRL = null; + mUpdatingCRL = CRL_UPDATE_DONE; + if (Debug.on()) + Debug.printStackTrace(e); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_SIGN_OR_STORE_CRL", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_FAILED_CONSTRUCTING_CRL", e.toString())); + } catch (NoSuchAlgorithmException e) { + newX509CRL = null; + mUpdatingCRL = CRL_UPDATE_DONE; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_SIGN_CRL", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_FAILED_CONSTRUCTING_CRL", e.toString())); + } catch (CRLException e) { + newX509CRL = null; + mUpdatingCRL = CRL_UPDATE_DONE; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_SIGN_CRL", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_FAILED_CONSTRUCTING_CRL", e.toString())); + } catch (X509ExtensionException e) { + newX509CRL = null; + mUpdatingCRL = CRL_UPDATE_DONE; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_SIGN_CRL", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_FAILED_CONSTRUCTING_CRL", e.toString())); + } catch (OutOfMemoryError e) { + newX509CRL = null; + mUpdatingCRL = CRL_UPDATE_DONE; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_SIGN_CRL", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_FAILED_CONSTRUCTING_CRL", e.toString())); + } + + try { + mSplits[9] -= System.currentTimeMillis(); + mUpdatingCRL = CRL_PUBLISHING_STARTED; + publishCRL(newX509CRL); + newX509CRL = null; + mSplits[9] += System.currentTimeMillis(); + } catch (EBaseException e) { + newX509CRL = null; + mUpdatingCRL = CRL_UPDATE_DONE; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_PUBLISH_CRL", mCRLNumber.toString(), e.toString())); + } catch (OutOfMemoryError e) { + newX509CRL = null; + mUpdatingCRL = CRL_UPDATE_DONE; + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_PUBLISH_CRL", mCRLNumber.toString(), e.toString())); + } + } + + if (isDeltaCRLEnabled() && mDeltaCRLSize > -1 && mSchemaCounter > 0) { + mDeltaCRLNumber = mNextDeltaCRLNumber; + mNextDeltaCRLNumber = mDeltaCRLNumber.add(BigInteger.ONE); + } + + if ((!(mEnableDailyUpdates && mExtendedTimeList)) || mSchemaCounter == 0) mSchemaCounter++; + if ((mEnableDailyUpdates && mExtendedTimeList && mSchemaCounter >= mTimeListSize) || + (mUpdateSchema > 1 && mSchemaCounter >= mUpdateSchema)) mSchemaCounter = 0; + mLastDay = mCurrentDay; + + mUpdatingCRL = CRL_UPDATE_DONE; + notifyAll(); + } + + /** + * publish CRL. called from updateCRLNow() and init(). + */ + + public void publishCRL() + throws EBaseException { + publishCRL(null); + } + + protected void publishCRL(X509CRLImpl x509crl) + throws EBaseException { + publishCRL(x509crl, false); + } + + protected void publishCRL(X509CRLImpl x509crl, boolean isDeltaCRL) + throws EBaseException { + SessionContext sc = SessionContext.getContext(); + + IStatsSubsystem statsSub = (IStatsSubsystem)CMS.getSubsystem("stats"); + if (statsSub != null) { + statsSub.startTiming("crl_publishing"); + } + + if (mCountMod == 0) { + sc.put(SC_CRL_COUNT, Integer.toString(mCount)); + } else { + sc.put(SC_CRL_COUNT, Integer.toString(mCount%mCountMod)); + } + mCount++; + sc.put(SC_ISSUING_POINT_ID, mId); + if (isDeltaCRL) { + sc.put(SC_IS_DELTA_CRL, "true"); + } else { + sc.put(SC_IS_DELTA_CRL, "false"); + } + + ICRLIssuingPointRecord crlRecord = null; + + CMS.debug("Publish CRL"); + try { + if (x509crl == null) { + crlRecord = mCRLRepository.readCRLIssuingPointRecord(mId); + if (crlRecord != null) { + byte[] crl = (isDeltaCRL) ? crlRecord.getDeltaCRL() : crlRecord.getCRL(); + + if (crl != null) { + x509crl = new X509CRLImpl(crl); + } + } + } + if (x509crl != null && + mPublisherProcessor != null && mPublisherProcessor.enabled()) { + Enumeration rules = mPublisherProcessor.getRules(IPublisherProcessor.PROP_LOCAL_CRL); + if (rules == null || !rules.hasMoreElements()) { + CMS.debug("CRL publishing is not enabled."); + } else { + if (mPublishDN != null) { + mPublisherProcessor.publishCRL(mPublishDN, x509crl); + CMS.debug("CRL published to " + mPublishDN); + } else { + mPublisherProcessor.publishCRL(x509crl,getId()); + CMS.debug("CRL published."); + } + } + } + } catch (Exception e) { + CMS.debug("Could not publish CRL. Error " + e); + CMS.debug("Could not publish CRL. ID " + mId); + throw new EErrorPublishCRL( + CMS.getUserMessage("CMS_CA_ERROR_PUBLISH_CRL", mId, e.toString())); + } finally { + if (statsSub != null) { + statsSub.endTiming("crl_publishing"); + } + } + } + + protected void log(int level, String msg) { + mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_CA, level, + "CRLIssuingPoint " + mId + " - " + msg); + } + + void setConfigParam(String name, String value) { + mConfigStore.putString(name, value); + } + + class RevocationRequestListener implements IRequestListener { + + public void init(ISubsystem sys, IConfigStore config) + throws EBaseException { + } + + public void set(String name, String val) { + } + + public void accept(IRequest r) { + String requestType = r.getRequestType(); + + if (requestType.equals(IRequest.REVOCATION_REQUEST) || + requestType.equals(IRequest.UNREVOCATION_REQUEST) || + requestType.equals(IRequest.CLA_CERT4CRL_REQUEST) || + requestType.equals(IRequest.CLA_UNCERT4CRL_REQUEST)) { + CMS.debug("Revocation listener called."); + // check if serial number is in begin/end range if set. + if (mBeginSerial != null || mEndSerial != null) { + CMS.debug( + "Checking if serial number is between " + + mBeginSerial + " and " + mEndSerial); + BigInteger[] serialNos = + r.getExtDataInBigIntegerArray(IRequest.OLD_SERIALS); + + if (serialNos == null || serialNos.length == 0) { + X509CertImpl oldCerts[] = + r.getExtDataInCertArray(IRequest.OLD_CERTS); + + if (oldCerts == null || oldCerts.length == 0) + return; + serialNos = new BigInteger[oldCerts.length]; + for (int i = 0; i < oldCerts.length; i++) { + serialNos[i] = oldCerts[i].getSerialNumber(); + } + } + + boolean inRange = false; + + for (int i = 0; i < serialNos.length; i++) { + if ((mBeginSerial == null || + serialNos[i].compareTo(mBeginSerial) >= 0) && + (mEndSerial == null || + serialNos[i].compareTo(mEndSerial) <= 0)) { + inRange = true; + } + } + if (!inRange) { + return; + } + } + + if (mAlwaysUpdate) { + try { + updateCRLNow(); + r.setExtData(mCrlUpdateStatus, IRequest.RES_SUCCESS); + if (mPublisherProcessor != null) { + r.setExtData(mCrlPublishStatus, IRequest.RES_SUCCESS); + } + } catch (EErrorPublishCRL e) { + // error already logged in updateCRLNow(); + r.setExtData(mCrlUpdateStatus, IRequest.RES_SUCCESS); + if (mPublisherProcessor != null) { + r.setExtData(mCrlPublishStatus, IRequest.RES_ERROR); + r.setExtData(mCrlPublishError, e); + } + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_UPDATE_CRL", e.toString())); + r.setExtData(mCrlUpdateStatus, IRequest.RES_ERROR); + r.setExtData(mCrlUpdateError, e); + } catch (Exception e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ISSUING_UPDATE_CRL", e.toString())); + if (Debug.on()) + Debug.printStackTrace(e); + r.setExtData(mCrlUpdateStatus, IRequest.RES_ERROR); + r.setExtData(mCrlUpdateError, + new EBaseException( + CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString()))); + } + } + } + } + } +} + + +class CertRecProcessor implements IElementProcessor { + private Hashtable mCRLCerts = null; + private boolean mAllowExtensions = false; + private ILogger mLogger; + private CRLIssuingPoint mIP = null; + + private boolean mIssuingDistPointAttempted = false; + private boolean mIssuingDistPointEnabled = false; + private BitArray mOnlySomeReasons = null; + + public CertRecProcessor(Hashtable crlCerts, CRLIssuingPoint ip, ILogger logger, boolean allowExtensions) { + mCRLCerts = crlCerts; + mLogger = logger; + mIP = ip; + mAllowExtensions = allowExtensions; + mIssuingDistPointAttempted = false; + mIssuingDistPointEnabled = false; + mOnlySomeReasons = null; + } + + private boolean initCRLIssuingDistPointExtension() { + boolean result = false; + CMSCRLExtensions exts = null; + + if(mIssuingDistPointAttempted == true) { + if((mIssuingDistPointEnabled == true) && (mOnlySomeReasons != null )) { + return true; + } else { + return false; + } + } + + mIssuingDistPointAttempted = true; + exts = (CMSCRLExtensions) mIP.getCRLExtensions(); + if(exts == null) { + return result; + } + boolean isIssuingDistPointExtEnabled = false; + isIssuingDistPointExtEnabled = exts.isCRLExtensionEnabled(IssuingDistributionPointExtension.NAME); + if(isIssuingDistPointExtEnabled == false) { + mIssuingDistPointEnabled = false; + return false; + } + + mIssuingDistPointEnabled = true; + + //Get info out of the IssuingDistPointExtension + CRLExtensions ext = new CRLExtensions(); + Vector extNames = exts.getCRLExtensionNames(); + for (int i = 0; i < extNames.size(); i++) { + String extName = (String) extNames.elementAt(i); + if (extName.equals(IssuingDistributionPointExtension.NAME)) { + exts.addToCRLExtensions(ext, extName, null); + } + } + Extension issuingDistExt = null; + try { + issuingDistExt = ext.get(IssuingDistributionPointExtension.NAME); + } catch (Exception e) { + } + + IssuingDistributionPointExtension iExt = null; + if(issuingDistExt != null) + iExt = (IssuingDistributionPointExtension) issuingDistExt; + IssuingDistributionPoint issuingDistributionPoint = null; + if(iExt != null) + issuingDistributionPoint = iExt.getIssuingDistributionPoint(); + + BitArray onlySomeReasons = null; + + if(issuingDistributionPoint != null) + onlySomeReasons = issuingDistributionPoint.getOnlySomeReasons(); + + boolean applyReasonMatch = false; + boolean reasonMatch = true; + + if(onlySomeReasons != null) { + applyReasonMatch = !onlySomeReasons.toString().equals("0000000"); + CMS.debug("applyReasonMatch " + applyReasonMatch); + if(applyReasonMatch == true) { + mOnlySomeReasons = onlySomeReasons; + result = true; + } + } + return result; + } + + private boolean checkOnlySomeReasonsExtension(CRLExtensions entryExts) + { + boolean includeCert = true; + //This is exactly how the Pretty Print code obtains the reason code + //through the extensions + if(entryExts == null) { + return includeCert; + } + + Extension crlReasonExt = null; + try { + crlReasonExt = entryExts.get(CRLReasonExtension.NAME); + } catch (Exception e) { + return includeCert; + } + + RevocationReason reason = null; + int reasonIndex = 0; + if(crlReasonExt != null) { + try { + CRLReasonExtension theReason = (CRLReasonExtension) crlReasonExt; + reason = (RevocationReason) theReason.get("value"); + reasonIndex = reason.toInt(); + CMS.debug("revoked reason " + reason); + } catch (Exception e) { + return includeCert; + } + } else { + return includeCert; + } + boolean reasonMatch = false; + if(reason != null) { + if(mOnlySomeReasons != null) { + reasonMatch = mOnlySomeReasons.get(reasonIndex); + if(reasonMatch != true) { + includeCert = false; + } else { + CMS.debug("onlySomeReasons match! reason: " + reason); + } + } + } + + return includeCert; + } + + public boolean checkRevokedCertExtensions(CRLExtensions crlExtensions) + { + //For now just check the onlySomeReason CRL IssuingDistributionPoint extension + + boolean includeCert = true; + if((crlExtensions == null) || (mAllowExtensions == false)) { + return includeCert; + } + boolean inited = initCRLIssuingDistPointExtension(); + + //If the CRLIssuingDistPointExtension is not available or + // if onlySomeReasons does not apply, bail. + if(inited == false) { + return includeCert; + } + + //Check the onlySomeReasonsExtension + includeCert = checkOnlySomeReasonsExtension(crlExtensions); + + return includeCert; + } + + public void process(Object o) throws EBaseException { + try { + CertRecord certRecord = (CertRecord) o; + + CRLExtensions entryExt = null, crlExts = null; + BigInteger serialNumber = certRecord.getSerialNumber(); + Date revocationDate = certRecord.getRevocationDate(); + IRevocationInfo revInfo = certRecord.getRevocationInfo(); + + if (revInfo != null) { + crlExts = revInfo.getCRLEntryExtensions(); + entryExt = mIP.getRequiredEntryExtensions(crlExts); + } + RevokedCertificate newRevokedCert = + new RevokedCertImpl(serialNumber, revocationDate, entryExt); + + boolean includeCert = checkRevokedCertExtensions(crlExts); + + if (includeCert == true) { + mCRLCerts.put(serialNumber, (RevokedCertificate) newRevokedCert); + if (serialNumber != null) { + CMS.debug("Putting certificate serial: 0x"+serialNumber.toString(16)+" into CRL hashtable"); + } + } + } catch (EBaseException e) { + CMS.debug( + "CA failed constructing CRL entry: " + + (mCRLCerts.size() + 1) + " " + e); + throw new ECAException(CMS.getUserMessage("CMS_CA_FAILED_CONSTRUCTING_CRL", e.toString())); + } + } +} + -- cgit