From 621d9e5c413e561293d7484b93882d985b3fe15f Mon Sep 17 00:00:00 2001 From: Endi Sukma Dewata Date: Sat, 24 Mar 2012 02:27:47 -0500 Subject: Removed unnecessary pki folder. Previously the source code was located inside a pki folder. This folder was created during svn migration and is no longer needed. This folder has now been removed and the contents have been moved up one level. Ticket #131 --- base/ca/src/com/netscape/ca/CAPolicy.java | 138 + base/ca/src/com/netscape/ca/CAService.java | 2122 +++++++++++++ base/ca/src/com/netscape/ca/CMSCRLExtensions.java | 711 +++++ base/ca/src/com/netscape/ca/CRLIssuingPoint.java | 3140 ++++++++++++++++++++ .../src/com/netscape/ca/CRLWithExpiredCerts.java | 68 + .../src/com/netscape/ca/CertificateAuthority.java | 2024 +++++++++++++ base/ca/src/com/netscape/ca/SigningUnit.java | 389 +++ 7 files changed, 8592 insertions(+) create mode 100644 base/ca/src/com/netscape/ca/CAPolicy.java create mode 100644 base/ca/src/com/netscape/ca/CAService.java create mode 100644 base/ca/src/com/netscape/ca/CMSCRLExtensions.java create mode 100644 base/ca/src/com/netscape/ca/CRLIssuingPoint.java create mode 100644 base/ca/src/com/netscape/ca/CRLWithExpiredCerts.java create mode 100644 base/ca/src/com/netscape/ca/CertificateAuthority.java create mode 100644 base/ca/src/com/netscape/ca/SigningUnit.java (limited to 'base/ca/src/com/netscape') diff --git a/base/ca/src/com/netscape/ca/CAPolicy.java b/base/ca/src/com/netscape/ca/CAPolicy.java new file mode 100644 index 000000000..4df28d344 --- /dev/null +++ b/base/ca/src/com/netscape/ca/CAPolicy.java @@ -0,0 +1,138 @@ +// --- 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 com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.policy.IPolicyProcessor; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.profile.IProfileSubsystem; +import com.netscape.certsrv.request.IPolicy; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.PolicyResult; +import com.netscape.cmscore.policy.GenericPolicyProcessor; +import com.netscape.cmscore.util.Debug; + +/** + * XXX Just inherit 'GenericPolicyProcessor' (from RA) for now. + * This really bad. need to make a special case just for connector. + * would like a much better way of doing this to handle both EE and + * connectors. + * XXX2 moved to just implement IPolicy since GenericPolicyProcessor is + * unuseable for CA. + * + * @deprecated + * @version $Revision$, $Date$ + */ +public class CAPolicy implements IPolicy { + IConfigStore mConfig = null; + ICertificateAuthority mCA = null; + + public static String PROP_PROCESSOR = + "processor"; + // These are the different types of policy that are + // allowed for the "processor" property + public static String PR_TYPE_CLASSIC = "classic"; + + // XXX this way for now since generic just works for EE. + public GenericPolicyProcessor mPolicies = null; + + public CAPolicy() { + } + + public IPolicyProcessor getPolicyProcessor() { + return mPolicies; + } + + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mCA = (ICertificateAuthority) owner; + mConfig = config; + + String processorType = // XXX - need to upgrade 4.2 + config.getString(PROP_PROCESSOR, PR_TYPE_CLASSIC); + + Debug.trace("selected policy processor = " + processorType); + if (processorType.equals(PR_TYPE_CLASSIC)) { + mPolicies = new GenericPolicyProcessor(); + } else { + throw new EBaseException("Unknown policy processor type (" + + processorType + ")"); + } + + mPolicies.init(mCA, mConfig); + } + + public boolean isProfileRequest(IRequest request) { + String profileId = request.getExtDataInString("profileId"); + + if (profileId == null || profileId.equals("")) + return false; + else + return true; + } + + /** + */ + public PolicyResult apply(IRequest r) { + if (r == null) { + Debug.trace("in CAPolicy.apply(request=null)"); + return PolicyResult.REJECTED; + } + + Debug.trace("in CAPolicy.apply(requestType=" + + r.getRequestType() + ",requestId=" + + r.getRequestId().toString() + ",requestStatus=" + + r.getRequestStatus().toString() + ")"); + + if (isProfileRequest(r)) { + Debug.trace("CAPolicy: Profile-base Request " + + r.getRequestId().toString()); + + CMS.debug("CAPolicy: requestId=" + + r.getRequestId().toString()); + + String profileId = r.getExtDataInString("profileId"); + + if (profileId == null || profileId.equals("")) { + return PolicyResult.REJECTED; + } + + IProfileSubsystem ps = (IProfileSubsystem) + CMS.getSubsystem("profile"); + + try { + IProfile profile = ps.getProfile(profileId); + + r.setExtData("dbStatus", "NOT_UPDATED"); + profile.populate(r); + profile.validate(r); + return PolicyResult.ACCEPTED; + } catch (EBaseException e) { + CMS.debug("CAPolicy: " + e.toString()); + return PolicyResult.REJECTED; + } + } + Debug.trace("mPolicies = " + mPolicies.getClass()); + return mPolicies.apply(r); + } + +} diff --git a/base/ca/src/com/netscape/ca/CAService.java b/base/ca/src/com/netscape/ca/CAService.java new file mode 100644 index 000000000..62bae3b5f --- /dev/null +++ b/base/ca/src/com/netscape/ca/CAService.java @@ -0,0 +1,2122 @@ +// --- 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.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.cert.CRLException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import netscape.security.extensions.CertInfo; +import netscape.security.util.BigInt; +import netscape.security.util.DerValue; +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.BasicConstraintsExtension; +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.CertificateAlgorithmId; +import netscape.security.x509.CertificateChain; +import netscape.security.x509.CertificateExtensions; +import netscape.security.x509.CertificateIssuerName; +import netscape.security.x509.CertificateSerialNumber; +import netscape.security.x509.CertificateSubjectName; +import netscape.security.x509.CertificateValidity; +import netscape.security.x509.Extension; +import netscape.security.x509.LdapV3DNStrConverter; +import netscape.security.x509.PKIXExtensions; +import netscape.security.x509.RevocationReason; +import netscape.security.x509.RevokedCertImpl; +import netscape.security.x509.SerialNumber; +import netscape.security.x509.X500Name; +import netscape.security.x509.X500NameAttrMap; +import netscape.security.x509.X509CRLImpl; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; +import netscape.security.x509.X509ExtensionException; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authority.IAuthority; +import com.netscape.certsrv.authority.ICertAuthority; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.MetaInfo; +import com.netscape.certsrv.base.SessionContext; +import com.netscape.certsrv.ca.ECAException; +import com.netscape.certsrv.ca.ICAService; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.connector.IConnector; +import com.netscape.certsrv.dbs.Modification; +import com.netscape.certsrv.dbs.ModificationSet; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertRecordList; +import com.netscape.certsrv.dbs.crldb.ICRLIssuingPointRecord; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.profile.EProfileException; +import com.netscape.certsrv.profile.IProfile; +import com.netscape.certsrv.profile.IProfileSubsystem; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IService; +import com.netscape.cmscore.base.SubsystemRegistry; +import com.netscape.cmscore.connector.HttpConnector; +import com.netscape.cmscore.connector.LocalConnector; +import com.netscape.cmscore.connector.RemoteAuthority; +import com.netscape.cmscore.crmf.CRMFParser; +import com.netscape.cmscore.crmf.PKIArchiveOptionsContainer; +import com.netscape.cmscore.dbs.CertRecord; +import com.netscape.cmscore.dbs.CertificateRepository; +import com.netscape.cmscore.dbs.RevocationInfo; +import com.netscape.cmscore.util.Debug; +import com.netscape.cmsutil.util.Utils; + +/** + * Request Service for CertificateAuthority. + */ +public class CAService implements ICAService, IService { + + public static final String CRMF_REQUEST = "CRMFRequest"; + public static final String CHALLENGE_PHRASE = "challengePhrase"; + public static final String SERIALNO_ARRAY = "serialNoArray"; + + // CCA->CLA connector + protected static IConnector mCLAConnector = null; + + private ICertificateAuthority mCA = null; + private Hashtable mServants = new Hashtable(); + private IConnector mKRAConnector = null; + private IConfigStore mConfig = null; + private boolean mArchivalRequired = true; + private Hashtable mCRLIssuingPoints = new Hashtable(); + + private ILogger mSignedAuditLogger = CMS.getSignedAuditLogger(); + private final static String LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST = + "LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST_4"; + + public CAService(ICertificateAuthority ca) { + mCA = ca; + + // init services. + mServants.put( + IRequest.ENROLLMENT_REQUEST, + new serviceIssue(this)); + mServants.put( + IRequest.RENEWAL_REQUEST, + new serviceRenewal(this)); + mServants.put( + IRequest.REVOCATION_REQUEST, + new serviceRevoke(this)); + mServants.put( + IRequest.CMCREVOKE_REQUEST, + new serviceRevoke(this)); + mServants.put( + IRequest.REVOCATION_CHECK_CHALLENGE_REQUEST, + new serviceCheckChallenge(this)); + mServants.put( + IRequest.GETCERTS_FOR_CHALLENGE_REQUEST, + new getCertsForChallenge(this)); + mServants.put( + IRequest.UNREVOCATION_REQUEST, + new serviceUnrevoke(this)); + mServants.put( + IRequest.GETCACHAIN_REQUEST, + new serviceGetCAChain(this)); + mServants.put( + IRequest.GETCRL_REQUEST, + new serviceGetCRL(this)); + mServants.put( + IRequest.GETREVOCATIONINFO_REQUEST, + new serviceGetRevocationInfo(this)); + mServants.put( + IRequest.GETCERTS_REQUEST, + new serviceGetCertificates(this)); + mServants.put( + IRequest.CLA_CERT4CRL_REQUEST, + new serviceCert4Crl(this)); + mServants.put( + IRequest.CLA_UNCERT4CRL_REQUEST, + new serviceUnCert4Crl(this)); + mServants.put( + IRequest.GETCERT_STATUS_REQUEST, + new getCertStatus(this)); + } + + public void init(IConfigStore config) throws EBaseException { + mConfig = config; + + try { + // MOVED TO com.netscape.certsrv.apps.CMS + // java.security.Security.addProvider(new netscape.security.provider.CMS()); + // java.security.Provider pr = java.security.Security.getProvider("CMS"); + // if (pr != null) { + // ; + // } + // else + // Debug.trace("Something is wrong in CMS install !"); + java.security.cert.CertificateFactory cf = java.security.cert.CertificateFactory.getInstance("X.509"); + + Debug.trace("CertificateFactory Type : " + cf.getType()); + Debug.trace("CertificateFactory Provider : " + cf.getProvider().getInfo()); + } catch (java.security.cert.CertificateException e) { + Debug.trace("Something is happen in install CMS provider !" + e.toString()); + } + } + + public void startup() throws EBaseException { + IConfigStore kraConfig = mConfig.getSubStore("KRA"); + + if (kraConfig != null) { + mArchivalRequired = kraConfig.getBoolean( + "archivalRequired", true); + mKRAConnector = getConnector(kraConfig); + if (mKRAConnector != null) { + if (Debug.ON) { + Debug.trace("Started KRA Connector"); + } + mKRAConnector.start(); + } + } + + // clone ca to CLA (clone master) connector + IConfigStore claConfig = mConfig.getSubStore("CLA"); + + if (claConfig != null) { + mCLAConnector = getConnector(claConfig); + if (mCLAConnector != null) { + CMS.debug(CMS.getLogMessage("CMSCORE_CA_START_CONNECTOR")); + if (Debug.ON) { + Debug.trace("Started CLA Connector in CCA"); + } + mCLAConnector.start(); + } + } + } + + protected ICertificateAuthority getCA() { + return mCA; + } + + public IConnector getKRAConnector() { + return mKRAConnector; + } + + public void setKRAConnector(IConnector c) { + mKRAConnector = c; + } + + public IConnector getConnector(IConfigStore config) + throws EBaseException { + IConnector connector = null; + + if (config == null || config.size() <= 0) { + return null; + } + boolean enable = config.getBoolean("enable", true); + // provide a way to register a 3rd connector into RA + String extConnector = config.getString("class", null); + + if (extConnector != null) { + try { + connector = (IConnector) + Class.forName(extConnector).newInstance(); + // connector.start() will be called later on + return connector; + } catch (Exception e) { + // ignore external class if error + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_LOAD_CONNECTOR", extConnector, e.toString())); + } + } + + if (!enable) + return null; + boolean local = config.getBoolean("local"); + IAuthority authority = null; + + if (local) { + String id = config.getString("id"); + + authority = (IAuthority) SubsystemRegistry.getInstance().get(id); + if (authority == null) { + String msg = "local authority " + id + " not found."; + + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_AUTHORITY_NOT_FOUND", id)); + throw new EBaseException(msg); + } + connector = new LocalConnector((ICertAuthority) mCA, authority); + // log(ILogger.LL_INFO, "local Connector to "+id+" inited"); + } else { + String host = config.getString("host"); + int port = config.getInteger("port"); + String uri = config.getString("uri"); + String nickname = config.getString("nickName", null); + int resendInterval = config.getInteger("resendInterval", -1); + // Inserted by beomsuk + int timeout = config.getInteger("timeout", 0); + // Insert end + // Changed by beomsuk + //RemoteAuthority remauthority = + // new RemoteAuthority(host, port, uri); + RemoteAuthority remauthority = + new RemoteAuthority(host, port, uri, timeout); + + // Change end + if (nickname == null) + nickname = mCA.getNickname(); + // Changed by beomsuk + //connector = + // new HttpConnector(mCA, nickname, remauthority, resendInterval); + if (timeout == 0) + connector = new HttpConnector((IAuthority) mCA, nickname, remauthority, resendInterval, config); + else + connector = + new HttpConnector((IAuthority) mCA, nickname, remauthority, resendInterval, config, timeout); + // Change end + + // log(ILogger.LL_INFO, "remote authority "+ + // host+":"+port+" "+uri+" inited"); + } + return connector; + } + + public boolean isProfileRequest(IRequest request) { + String profileId = request.getExtDataInString("profileId"); + + if (profileId == null || profileId.equals("")) + return false; + else + return true; + } + + /** + * After population of defaults, and constraint validation, + * the profile request is processed here. + */ + public void serviceProfileRequest(IRequest request) + throws EBaseException { + CMS.debug("CAService: serviceProfileRequest requestId=" + + request.getRequestId().toString()); + + String profileId = request.getExtDataInString("profileId"); + + if (profileId == null || profileId.equals("")) { + throw new EBaseException("profileId not found"); + } + + IProfileSubsystem ps = (IProfileSubsystem) + CMS.getSubsystem("profile"); + IProfile profile = null; + + try { + profile = ps.getProfile(profileId); + } catch (EProfileException e) { + } + if (profile == null) { + throw new EProfileException("Profile not found " + profileId); + } + + // assumed rejected + request.setExtData("dbStatus", "NOT_UPDATED"); + + // profile.populate(request); + profile.validate(request); + profile.execute(request); + + // This function is called only from ConnectorServlet + + // serialize to request queue + } + + /** + * method interface for IService + *

+ * + *

    + *
  • signed.audit LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST used whenever a user private key archive + * request is made. This is an option in a cert enrollment request detected by an RA or a CA, so, if selected, it + * should be logged immediately following the certificate request. + *
+ * + * @param request a certificate enrollment request from an RA or CA + * @return true or false + */ + public boolean serviceRequest(IRequest request) { + String auditMessage = null; + String auditSubjectID = auditSubjectID(); + String auditRequesterID = auditRequesterID(); + String auditArchiveID = ILogger.SIGNED_AUDIT_NON_APPLICABLE; + + boolean completed = false; + + // short cut profile-based request + if (isProfileRequest(request)) { + try { + CMS.debug("CAServic: x0 requestStatus=" + + request.getRequestStatus().toString() + " instance=" + request); + serviceProfileRequest(request); + request.setExtData(IRequest.RESULT, IRequest.RES_SUCCESS); + CMS.debug("CAServic: x1 requestStatus=" + request.getRequestStatus().toString()); + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditArchiveID); + + audit(auditMessage); + + return true; + } catch (EBaseException e) { + CMS.debug("CAServic: x2 requestStatus=" + request.getRequestStatus().toString()); + // need to put error into the request + CMS.debug("CAService: serviceRequest " + e.toString()); + request.setExtData(IRequest.RESULT, IRequest.RES_ERROR); + request.setExtData(IRequest.ERROR, e.toString()); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditArchiveID); + + audit(auditMessage); + + return false; + } + } + + String type = request.getRequestType(); + IServant servant = mServants.get(type); + + if (servant == null) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_INVALID_REQUEST_TYPE", type)); + request.setExtData(IRequest.RESULT, IRequest.RES_ERROR); + request.setExtData(IRequest.ERROR, + new ECAException(CMS.getUserMessage("CMS_CA_UNRECOGNIZED_REQUEST_TYPE", type))); + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditArchiveID); + + audit(auditMessage); + + return true; + } + + try { + // send request to KRA first + if (type.equals(IRequest.ENROLLMENT_REQUEST) && + isPKIArchiveOptionPresent(request) && mKRAConnector != null) { + if (Debug.ON) { + Debug.trace("*** Sending enrollment request to KRA"); + } + boolean sendStatus = mKRAConnector.send(request); + + if (mArchivalRequired == true) { + if (sendStatus == false) { + request.setExtData(IRequest.RESULT, + IRequest.RES_ERROR); + request.setExtData(IRequest.ERROR, + new ECAException(CMS.getUserMessage("CMS_CA_SEND_KRA_REQUEST"))); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditArchiveID); + + audit(auditMessage); + + return true; + } else { + if (request.getExtDataInString(IRequest.ERROR) != null) { + request.setExtData(IRequest.RESULT, IRequest.RES_SUCCESS); + request.deleteExtData(IRequest.ERROR); + } + } + if (request.getExtDataInString(IRequest.ERROR) != null) { + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditArchiveID); + + audit(auditMessage); + + return true; + } + } + } else { + if (Debug.ON) { + Debug.trace("*** NOT Send to KRA type=" + type + " ENROLLMENT=" + IRequest.ENROLLMENT_REQUEST); + } + } + + completed = servant.service(request); + request.setExtData(IRequest.RESULT, IRequest.RES_SUCCESS); + } catch (EBaseException e) { + request.setExtData(IRequest.RESULT, IRequest.RES_ERROR); + request.setExtData(IRequest.ERROR, e); + + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST, + auditSubjectID, + ILogger.FAILURE, + auditRequesterID, + auditArchiveID); + + audit(auditMessage); + + return true; + } + + // XXX in case of key archival this may not always be the case. + if (Debug.ON) + Debug.trace("serviceRequest completed = " + completed); + + if (!(type.equals(IRequest.REVOCATION_REQUEST) || + type.equals(IRequest.UNREVOCATION_REQUEST) || type.equals(IRequest.CMCREVOKE_REQUEST))) { + // store a message in the signed audit log file + auditMessage = CMS.getLogMessage( + LOGGING_SIGNED_AUDIT_PRIVATE_KEY_ARCHIVE_REQUEST, + auditSubjectID, + ILogger.SUCCESS, + auditRequesterID, + auditArchiveID); + + audit(auditMessage); + } + + return completed; + } + + /** + * register CRL Issuing Point + */ + public void addCRLIssuingPoint(String id, ICRLIssuingPoint crlIssuingPoint) { + mCRLIssuingPoints.put(id, crlIssuingPoint); + } + + /** + * get CRL Issuing Point + */ + public Hashtable getCRLIssuingPoints() { + return mCRLIssuingPoints; + } + + /** + * Checks if PKIArchiveOption present in the request. + */ + private boolean isPKIArchiveOptionPresent(IRequest request) { + String crmfBlob = request.getExtDataInString( + IRequest.HTTP_PARAMS, CRMF_REQUEST); + + if (crmfBlob == null) { + if (Debug.ON) { + Debug.trace("CRMF not found"); + } + } else { + try { + PKIArchiveOptionsContainer opts[] = CRMFParser.getPKIArchiveOptions(crmfBlob); + + if (opts != null) { + return true; + } + } catch (IOException e) { + } + return false; + } + return false; + } + + /// + /// CA related routines. + /// + + public X509CertImpl issueX509Cert(X509CertInfo certi) + throws EBaseException { + return issueX509Cert(certi, null, null); + } + + /** + * issue cert for enrollment. + */ + public X509CertImpl issueX509Cert(X509CertInfo certi, String profileId, String rid) + throws EBaseException { + CMS.debug("issueX509Cert"); + X509CertImpl certImpl = issueX509Cert("", certi, false, null); + + CMS.debug("storeX509Cert " + certImpl.getSerialNumber()); + storeX509Cert(profileId, rid, certImpl); + CMS.debug("done storeX509Cert"); + return certImpl; + } + + X509CertImpl issueX509Cert(String rid, X509CertInfo certi) + throws EBaseException { + return issueX509Cert(rid, certi, false, null); + } + + /** + * issue cert for enrollment. + */ + void storeX509Cert(String profileId, String rid, X509CertImpl cert) + throws EBaseException { + storeX509Cert(rid, cert, false, null, null, null, profileId); + } + + /** + * issue cert for enrollment. + */ + void storeX509Cert(String rid, X509CertImpl cert, String crmfReqId) + throws EBaseException { + storeX509Cert(rid, cert, false, null, crmfReqId, null, null); + } + + void storeX509Cert(String rid, X509CertImpl cert, String crmfReqId, + String challengePassword) throws EBaseException { + storeX509Cert(rid, cert, false, null, crmfReqId, challengePassword, null); + } + + /** + * issue cert for enrollment and renewal. + * renewal is expected to have original cert serial no. in cert info + * field. + */ + X509CertImpl issueX509Cert(String rid, X509CertInfo certi, + boolean renewal, BigInteger oldSerialNo) + throws EBaseException { + String algname = null; + X509CertImpl cert = null; + + // NOTE: In this implementation, the "oldSerialNo" + // parameter is NOT used! + + boolean doUTF8 = mConfig.getBoolean("dnUTF8Encoding", false); + + CMS.debug("dnUTF8Encoding " + doUTF8); + + try { + // check required fields in certinfo. + if (certi.get(X509CertInfo.SUBJECT) == null || + certi.get(X509CertInfo.KEY) == null) { + + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_MISSING_ATTR")); + // XXX how do you reject a request in the service object ? + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_REQD_FIELDS_IN_CERTISSUE")); + } + + // set default cert version. If policies added a extensions + // the version would already be set to version 3. + if (certi.get(X509CertInfo.VERSION) == null) { + certi.set(X509CertInfo.VERSION, mCA.getDefaultCertVersion()); + } + + // set default validity if not set. + // validity would normally be set by policies or by + // agent or by authentication module. + CertificateValidity validity = (CertificateValidity) + certi.get(X509CertInfo.VALIDITY); + Date begin = null, end = null; + + if (validity != null) { + begin = (Date) + validity.get(CertificateValidity.NOT_BEFORE); + end = (Date) + validity.get(CertificateValidity.NOT_AFTER); + } + if (validity == null || + (begin.getTime() == 0 && end.getTime() == 0)) { + if (Debug.ON) { + Debug.trace("setting default validity"); + } + + begin = CMS.getCurrentDate(); + end = new Date(begin.getTime() + mCA.getDefaultValidity()); + certi.set(CertificateValidity.NAME, + new CertificateValidity(begin, end)); + } + + /* + * For non-CA certs, check if validity exceeds CA time. + * If so, set to CA's not after if default validity + * exceeds ca's not after. + */ + + // First find out if it is a CA cert + boolean is_ca = false; + CertificateExtensions exts = null; + BasicConstraintsExtension bc_ext = null; + + try { + exts = (CertificateExtensions) + certi.get(X509CertInfo.EXTENSIONS); + if (exts != null) { + Enumeration e = exts.getAttributes(); + + while (e.hasMoreElements()) { + netscape.security.x509.Extension ext = (netscape.security.x509.Extension) e.nextElement(); + + if (ext.getExtensionId().toString().equals(PKIXExtensions.BasicConstraints_Id.toString())) { + bc_ext = (BasicConstraintsExtension) ext; + } + } + + if (bc_ext != null) { + Boolean isCA = (Boolean) bc_ext.get(BasicConstraintsExtension.IS_CA); + is_ca = isCA.booleanValue(); + } + } // exts != null + } catch (Exception e) { + CMS.debug("EnrollDefault: getExtension " + e.toString()); + } + + Date caNotAfter = + mCA.getSigningUnit().getCertImpl().getNotAfter(); + + if (begin.after(caNotAfter)) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_PAST_VALIDITY")); + throw new ECAException(CMS.getUserMessage("CMS_CA_CERT_BEGIN_AFTER_CA_VALIDITY")); + } + + if (end.after(caNotAfter)) { + if (!is_ca) { + if (!mCA.isEnablePastCATime()) { + end = caNotAfter; + certi.set(CertificateValidity.NAME, + new CertificateValidity(begin, caNotAfter)); + CMS.debug("CAService: issueX509Cert: cert past CA's NOT_AFTER...ca.enablePastCATime != true...resetting"); + } else { + CMS.debug("CAService: issueX509Cert: cert past CA's NOT_AFTER...ca.enablePastCATime = true...not resetting"); + } + } else { + CMS.debug("CAService: issueX509Cert: CA cert issuance past CA's NOT_AFTER."); + } //!is_ca + mCA.log(ILogger.LL_INFO, CMS.getLogMessage("CMSCORE_CA_PAST_NOT_AFTER")); + } + + // check algorithm in certinfo. + AlgorithmId algid = null; + CertificateAlgorithmId algor = (CertificateAlgorithmId) + certi.get(X509CertInfo.ALGORITHM_ID); + + if (algor == null || algor.toString().equals(CertInfo.SERIALIZE_ALGOR.toString())) { + algname = mCA.getSigningUnit().getDefaultAlgorithm(); + algid = AlgorithmId.get(algname); + certi.set(X509CertInfo.ALGORITHM_ID, + new CertificateAlgorithmId(algid)); + } else { + algid = (AlgorithmId) + algor.get(CertificateAlgorithmId.ALGORITHM); + algname = algid.getName(); + } + } catch (CertificateException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_BAD_FIELD", e.toString())); + if (Debug.ON) { + e.printStackTrace(); + } + throw new ECAException( + CMS.getUserMessage("CMS_CA_ERROR_GETTING_FIELDS_IN_ISSUE")); + } catch (IOException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_BAD_FIELD", e.toString())); + if (Debug.ON) { + e.printStackTrace(); + } + throw new ECAException( + CMS.getUserMessage("CMS_CA_ERROR_GETTING_FIELDS_IN_ISSUE")); + } catch (NoSuchAlgorithmException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_ALG_NOT_SUPPORTED", algname)); + if (Debug.ON) { + e.printStackTrace(); + } + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED", algname)); + } + + // get old cert serial number if renewal + if (renewal) { + try { + CertificateSerialNumber serialno = (CertificateSerialNumber) + certi.get(X509CertInfo.SERIAL_NUMBER); + + if (serialno == null) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_NULL_SERIAL_NUMBER")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_RENEWREQ")); + } + SerialNumber serialnum = (SerialNumber) + serialno.get(CertificateSerialNumber.NUMBER); + + if (serialnum == null) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_NULL_SERIAL_NUMBER")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_RENEWREQ")); + } + } catch (CertificateException e) { + // not possible + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_NO_ORG_SERIAL", e.getMessage())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_RENEWREQ")); + } catch (IOException e) { + // not possible. + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_NO_ORG_SERIAL", e.getMessage())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_RENEWREQ")); + } + } + + // set issuer, serial number + try { + BigInteger serialNo = + mCA.getCertificateRepository().getNextSerialNumber(); + + certi.set(X509CertInfo.SERIAL_NUMBER, + new CertificateSerialNumber(serialNo)); + mCA.log(ILogger.LL_INFO, CMS.getLogMessage("CMSCORE_CA_SIGN_SERIAL", serialNo.toString(16))); + } catch (EBaseException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_NO_NEXT_SERIAL", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_NOSERIALNO", rid)); + } catch (CertificateException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SET_SERIAL", e.toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SET_SERIALNO_FAILED", rid)); + } catch (IOException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SET_SERIAL", e.toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SET_SERIALNO_FAILED", rid)); + } + + try { + certi.set(X509CertInfo.ISSUER, + new CertificateIssuerName(mCA.getX500Name())); + } catch (CertificateException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SET_ISSUER", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_SET_ISSUER_FAILED", rid)); + } catch (IOException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SET_ISSUER", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_SET_ISSUER_FAILED", rid)); + } + + byte[] utf8_encodingOrder = { DerValue.tag_UTF8String }; + + if (doUTF8 == true) { + try { + + CMS.debug("doUTF8 true, updating subject."); + + String subject = certi.get(X509CertInfo.SUBJECT).toString(); + + certi.set(X509CertInfo.SUBJECT, new CertificateSubjectName( + new X500Name(subject, + new LdapV3DNStrConverter(X500NameAttrMap.getDirDefault(), true), utf8_encodingOrder))); + + } catch (CertificateException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SET_SUBJECT", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_SET_ISSUER_FAILED", rid)); + } catch (IOException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SET_SUBJECT", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_SET_ISSUER_FAILED", rid)); + } + } + + CMS.debug("About to mCA.sign cert."); + cert = mCA.sign(certi, algname); + return cert; + } + + void storeX509Cert(String rid, X509CertImpl cert, + boolean renewal, BigInteger oldSerialNo) + throws EBaseException { + storeX509Cert(rid, cert, renewal, oldSerialNo, null, null, null); + } + + void storeX509Cert(String rid, X509CertImpl cert, + boolean renewal, BigInteger oldSerialNo, String crmfReqId, + String challengePassword, String profileId) throws EBaseException { + // now store in repository. + // if renewal, set the old serial number in the new cert, + // set the new serial number in the old cert. + + CMS.debug("In storeX509Cert"); + try { + BigInteger newSerialNo = cert.getSerialNumber(); + MetaInfo metaInfo = new MetaInfo(); + + if (profileId != null) + metaInfo.set("profileId", profileId); + if (rid != null) + metaInfo.set(CertRecord.META_REQUEST_ID, rid); + if (challengePassword != null && !challengePassword.equals("")) + metaInfo.set("challengePhrase", challengePassword); + if (crmfReqId != null) { + //System.out.println("Adding crmf reqid "+crmfReqId); + metaInfo.set(CertRecord.META_CRMF_REQID, crmfReqId); + } + if (renewal) + metaInfo.set(CertRecord.META_OLD_CERT, oldSerialNo.toString()); + mCA.getCertificateRepository().addCertificateRecord( + new CertRecord(newSerialNo, cert, metaInfo)); + + mCA.log(ILogger.LL_INFO, CMS.getLogMessage("CMSCORE_CA_STORE_SERIAL", cert.getSerialNumber().toString(16))); + if (renewal) { + + /* + mCA.getCertificateRepository().markCertificateAsRenewed( + BigIntegerMapper.BigIntegerToDB(oldSerialNo)); + mCA.mCertRepot.markCertificateAsRenewed(oldSerialNo); + */ + MetaInfo oldMeta = null; + CertRecord oldCertRec = (CertRecord) + mCA.getCertificateRepository().readCertificateRecord(oldSerialNo); + + if (oldCertRec == null) { + Exception e = + new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", + "Cannot read cert record for " + oldSerialNo)); + + e.printStackTrace(); + } + if (oldCertRec != null) + oldMeta = oldCertRec.getMetaInfo(); + if (oldMeta == null) { + if (Debug.ON) { + Debug.trace("No meta info! for " + oldSerialNo); + } + oldMeta = new MetaInfo(); + } else { + if (Debug.ON) { + System.out.println("Old meta info"); + Enumeration n = oldMeta.getElements(); + + while (n.hasMoreElements()) { + String name = n.nextElement(); + + System.out.println("name " + name + " value " + + oldMeta.get(name)); + } + } + } + oldMeta.set(CertRecord.META_RENEWED_CERT, + newSerialNo.toString()); + ModificationSet modSet = new ModificationSet(); + + modSet.add(CertRecord.ATTR_AUTO_RENEW, + Modification.MOD_REPLACE, + CertRecord.AUTO_RENEWAL_DONE); + modSet.add(ICertRecord.ATTR_META_INFO, + Modification.MOD_REPLACE, oldMeta); + mCA.getCertificateRepository().modifyCertificateRecord(oldSerialNo, modSet); + mCA.log(ILogger.LL_INFO, + CMS.getLogMessage("CMSCORE_CA_MARK_SERIAL", oldSerialNo.toString(16), newSerialNo.toString(16))); + if (Debug.ON) { + CertRecord check = (CertRecord) + mCA.getCertificateRepository().readCertificateRecord(oldSerialNo); + MetaInfo meta = check.getMetaInfo(); + + Enumeration n = oldMeta.getElements(); + + while (n.hasMoreElements()) { + String name = n.nextElement(); + + } + } + } + } catch (EBaseException e) { + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_NO_STORE_SERIAL", cert.getSerialNumber().toString(16))); + if (Debug.ON) + e.printStackTrace(); + throw e; + } + } + + /** + * revoke cert, check fields in crlentry, etc. + */ + public void revokeCert(RevokedCertImpl crlentry) + throws EBaseException { + revokeCert(crlentry, null); + } + + public void revokeCert(RevokedCertImpl crlentry, String requestId) + throws EBaseException { + BigInteger serialno = crlentry.getSerialNumber(); + Date revdate = crlentry.getRevocationDate(); + CRLExtensions crlentryexts = crlentry.getExtensions(); + + CertRecord certRec = (CertRecord) mCA.getCertificateRepository().readCertificateRecord(serialno); + + if (certRec == null) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CERT_NOT_FOUND", serialno.toString(16))); + throw new ECAException( + CMS.getUserMessage("CMS_CA_CANT_FIND_CERT_SERIAL", + "0x" + serialno.toString(16))); + } + + // allow revoking certs that are on hold. + String certStatus = certRec.getStatus(); + + if (certStatus.equals(ICertRecord.STATUS_REVOKED) || + certStatus.equals(ICertRecord.STATUS_REVOKED_EXPIRED)) { + throw new ECAException(CMS.getUserMessage("CMS_CA_CERT_ALREADY_REVOKED", + "0x" + Long.toHexString(serialno.longValue()))); + } + try { + mCA.getCertificateRepository().markAsRevoked(serialno, + new RevocationInfo(revdate, crlentryexts)); + mCA.log(ILogger.LL_INFO, CMS.getLogMessage("CMSCORE_CA_CERT_REVOKED", + serialno.toString(16))); + // inform all CRLIssuingPoints about revoked certificate + Enumeration eIPs = mCRLIssuingPoints.elements(); + + while (eIPs.hasMoreElements()) { + ICRLIssuingPoint ip = (ICRLIssuingPoint) eIPs.nextElement(); + + if (ip != null) { + boolean b = true; + + if (ip.isCACertsOnly()) { + X509CertImpl cert = certRec.getCertificate(); + + if (cert != null) + b = cert.getBasicConstraintsIsCA(); + } + if (ip.isProfileCertsOnly()) { + MetaInfo metaInfo = certRec.getMetaInfo(); + if (metaInfo != null) { + String profileId = (String) metaInfo.get("profileId"); + if (profileId != null) { + b = ip.checkCurrentProfile(profileId); + } + } + } + if (b) + ip.addRevokedCert(serialno, crlentry, requestId); + } + } + } catch (EBaseException e) { + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_ERROR_REVOCATION", serialno.toString(), e.toString())); + //e.printStackTrace(); + throw e; + } + return; + } + + /** + * unrevoke cert, check serial number, etc. + */ + void unrevokeCert(BigInteger serialNo) + throws EBaseException { + unrevokeCert(serialNo, null); + } + + void unrevokeCert(BigInteger serialNo, String requestId) + throws EBaseException { + CertRecord certRec = (CertRecord) mCA.getCertificateRepository().readCertificateRecord(serialNo); + + if (certRec == null) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CERT_NOT_FOUND", serialNo.toString(16))); + throw new ECAException( + CMS.getUserMessage("CMS_CA_CANT_FIND_CERT_SERIAL", + "0x" + serialNo.toString(16))); + } + RevocationInfo revInfo = (RevocationInfo) certRec.getRevocationInfo(); + CRLExtensions exts = null; + CRLReasonExtension reasonext = null; + + if (revInfo == null) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CERT_ON_HOLD", serialNo.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_IS_NOT_ON_HOLD", + serialNo.toString())); + } + exts = revInfo.getCRLEntryExtensions(); + if (exts != null) { + try { + reasonext = (CRLReasonExtension) + exts.get(CRLReasonExtension.NAME); + } catch (X509ExtensionException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CERT_ON_HOLD", serialNo.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_IS_NOT_ON_HOLD", + serialNo.toString())); + } + } else { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CERT_ON_HOLD", serialNo.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_IS_NOT_ON_HOLD", + serialNo.toString())); + } + // allow unrevoking certs that are on hold. + if ((certRec.getStatus().equals(ICertRecord.STATUS_REVOKED) || + certRec.getStatus().equals(ICertRecord.STATUS_REVOKED_EXPIRED)) && + reasonext != null && + reasonext.getReason() == RevocationReason.CERTIFICATE_HOLD) { + try { + mCA.getCertificateRepository().unmarkRevoked(serialNo, revInfo, + certRec.getRevokedOn(), certRec.getRevokedBy()); + mCA.log(ILogger.LL_INFO, CMS.getLogMessage("CMSCORE_CA_CERT_UNREVOKED", serialNo.toString(16))); + // inform all CRLIssuingPoints about unrevoked certificate + Enumeration eIPs = mCRLIssuingPoints.elements(); + + while (eIPs.hasMoreElements()) { + ICRLIssuingPoint ip = eIPs.nextElement(); + + if (ip != null) { + boolean b = true; + + if (ip.isCACertsOnly()) { + X509CertImpl cert = certRec.getCertificate(); + + if (cert != null) + b = cert.getBasicConstraintsIsCA(); + } + if (ip.isProfileCertsOnly()) { + MetaInfo metaInfo = certRec.getMetaInfo(); + if (metaInfo != null) { + String profileId = (String) metaInfo.get("profileId"); + if (profileId != null) { + b = ip.checkCurrentProfile(profileId); + } + } + } + if (b) + ip.addUnrevokedCert(serialNo, requestId); + } + } + } catch (EBaseException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CERT_ERROR_UNREVOKE", serialNo.toString(16))); + throw e; + } + } else { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CERT_ON_HOLD", serialNo.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_IS_NOT_ON_HOLD", + "0x" + serialNo.toString(16))); + } + + return; + } + + /** + * Signed Audit Log + * + * This method is called to store messages to the signed audit log. + *

+ * + * @param msg signed audit log message + */ + private void audit(String msg) { + // in this case, do NOT strip preceding/trailing whitespace + // from passed-in String parameters + + if (mSignedAuditLogger == null) { + return; + } + + mSignedAuditLogger.log(ILogger.EV_SIGNED_AUDIT, + null, + ILogger.S_SIGNED_AUDIT, + ILogger.LL_SECURITY, + msg); + } + + /** + * Signed Audit Log Subject ID + * + * This method is called to obtain the "SubjectID" for + * a signed audit log message. + *

+ * + * @return id string containing the signed audit log message SubjectID + */ + private String auditSubjectID() { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String subjectID = null; + + // Initialize subjectID + SessionContext auditContext = SessionContext.getExistingContext(); + + if (auditContext != null) { + subjectID = (String) + auditContext.get(SessionContext.USER_ID); + + if (subjectID != null) { + subjectID = subjectID.trim(); + } else { + subjectID = ILogger.NONROLEUSER; + } + } else { + subjectID = ILogger.UNIDENTIFIED; + } + + return subjectID; + } + + /** + * Signed Audit Log Requester ID + * + * This method is called to obtain the "RequesterID" for + * a signed audit log message. + *

+ * + * @return id string containing the signed audit log message RequesterID + */ + private String auditRequesterID() { + // if no signed audit object exists, bail + if (mSignedAuditLogger == null) { + return null; + } + + String requesterID = null; + + // Initialize requesterID + SessionContext auditContext = SessionContext.getExistingContext(); + + if (auditContext != null) { + requesterID = (String) + auditContext.get(SessionContext.REQUESTER_ID); + + if (requesterID != null) { + requesterID = requesterID.trim(); + } else { + requesterID = ILogger.UNIDENTIFIED; + } + } else { + requesterID = ILogger.UNIDENTIFIED; + } + + return requesterID; + } +} + +/// +/// servant classes +/// + +interface IServant { + public boolean service(IRequest request) throws EBaseException; +} + +class serviceIssue implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + + public serviceIssue(CAService service) { + mService = service; + mCA = mService.getCA(); + } + + public boolean service(IRequest request) + throws EBaseException { + // XXX This is ugly. should associate attributes with + // request types, not policy. + // XXX how do we know what to look for in request ? + + if (request.getExtDataInCertInfoArray(IRequest.CERT_INFO) != null) + return serviceX509(request); + else + return false; // Don't know what it is ????? + } + + public boolean serviceX509(IRequest request) + throws EBaseException { + // XXX This is ugly. should associate attributes with + // request types, not policy. + // XXX how do we know what to look for in request ? + X509CertInfo certinfos[] = + request.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (certinfos == null || certinfos[0] == null) { + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CERT_REQUEST_NOT_FOUND", request.getRequestId().toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_ISSUEREQ")); + } + String challengePassword = + request.getExtDataInString(CAService.CHALLENGE_PHRASE); + + X509CertImpl[] certs = new X509CertImpl[certinfos.length]; + String rid = request.getRequestId().toString(); + int i; + + for (i = 0; i < certinfos.length; i++) { + try { + certs[i] = mService.issueX509Cert(rid, certinfos[i]); + } catch (EBaseException e) { + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_ISSUE_ERROR", Integer.toString(i), rid, e.toString())); + throw e; + } + } + String crmfReqId = request.getExtDataInString(IRequest.CRMF_REQID); + EBaseException ex = null; + + for (i = 0; i < certs.length; i++) { + try { + mService.storeX509Cert(rid, certs[i], crmfReqId, challengePassword); + } catch (EBaseException e) { + e.printStackTrace(); + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_STORE_ERROR", Integer.toString(i), rid, e.toString())); + ex = e; // save to throw later. + break; + } + } + if (ex != null) { + for (int j = 0; j < i; j++) { + // delete the stored cert records from the database. + // we issue all or nothing. + BigInteger serialNo = + ((X509Certificate) certs[i]).getSerialNumber(); + + try { + mCA.getCertificateRepository().deleteCertificateRecord(serialNo); + } catch (EBaseException e) { + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_DELETE_CERT_ERROR", serialNo.toString(), e.toString())); + } + } + throw ex; + } + + request.setExtData(IRequest.ISSUED_CERTS, certs); + + return true; + } +} + +class serviceRenewal implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + + public serviceRenewal(CAService service) { + mService = service; + mCA = mService.getCA(); + } + + public boolean service(IRequest request) + throws EBaseException { + // XXX if one fails should all fail ? - can't backtrack. + X509CertInfo certinfos[] = + request.getExtDataInCertInfoArray(IRequest.CERT_INFO); + + if (certinfos == null || certinfos[0] == null) { + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CERT_REQUEST_NOT_FOUND", request.getRequestId().toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_RENEWREQ")); + } + X509CertImpl issuedCerts[] = new X509CertImpl[certinfos.length]; + + for (int j = 0; j < issuedCerts.length; j++) + issuedCerts[j] = null; + String svcerrors[] = new String[certinfos.length]; + + for (int k = 0; k < svcerrors.length; k++) + svcerrors[k] = null; + String rid = request.getRequestId().toString(); + + for (int i = 0; i < certinfos.length; i++) { + try { + // get old serial number. + SerialNumber serialnum = null; + + try { + CertificateSerialNumber serialno = (CertificateSerialNumber) + certinfos[i].get(X509CertInfo.SERIAL_NUMBER); + + if (serialno == null) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_NULL_SERIAL_NUMBER")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_RENEWREQ")); + } + serialnum = (SerialNumber) + serialno.get(CertificateSerialNumber.NUMBER); + } catch (IOException e) { + if (Debug.ON) + e.printStackTrace(); + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ERROR_GET_CERT", e.toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_RENEWREQ")); + } catch (CertificateException e) { + if (Debug.ON) + e.printStackTrace(); + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ERROR_GET_CERT", e.toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_RENEWREQ")); + } + if (serialnum == null) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_ERROR_GET_CERT", "")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_RENEWREQ")); + } + BigInt serialnumBigInt = serialnum.getNumber(); + BigInteger oldSerialNo = serialnumBigInt.toBigInteger(); + + // get cert record + CertRecord certRecord = (CertRecord) + mCA.getCertificateRepository().readCertificateRecord(oldSerialNo); + + if (certRecord == null) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_NOT_FROM_CA", oldSerialNo.toString())); + svcerrors[i] = new ECAException( + CMS.getUserMessage("CMS_CA_CANT_FIND_CERT_SERIAL", + oldSerialNo.toString())).toString(); + continue; + } + + // check if cert has been revoked. + String certStatus = certRecord.getStatus(); + + if (certStatus.equals(ICertRecord.STATUS_REVOKED) || + certStatus.equals(ICertRecord.STATUS_REVOKED_EXPIRED)) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_RENEW_REVOKED", oldSerialNo.toString())); + svcerrors[i] = new ECAException( + CMS.getUserMessage("CMS_CA_CANNOT_RENEW_REVOKED_CERT", + "0x" + oldSerialNo.toString(16))).toString(); + continue; + } + + // check if cert has already been renewed. + MetaInfo metaInfo = certRecord.getMetaInfo(); + + if (metaInfo != null) { + String renewed = (String) + metaInfo.get(ICertRecord.META_RENEWED_CERT); + + if (renewed != null) { + BigInteger serial = new BigInteger(renewed); + X509CertImpl cert = + mCA.getCertificateRepository().getX509Certificate(serial); + + if (cert == null) { + // something wrong + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_MISSING_RENEWED", serial.toString())); + svcerrors[i] = new ECAException( + CMS.getUserMessage("CMS_CA_ERROR_GETTING_RENEWED_CERT", + oldSerialNo.toString(), serial.toString())).toString(); + continue; + } + // get cert record + CertRecord cRecord = (CertRecord) + mCA.getCertificateRepository().readCertificateRecord(serial); + + if (cRecord == null) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_NOT_FROM_CA", serial.toString())); + svcerrors[i] = new ECAException( + CMS.getUserMessage("CMS_CA_CANT_FIND_CERT_SERIAL", + serial.toString())).toString(); + continue; + } + // Check renewed certificate already REVOKED or EXPIRED + String status = cRecord.getStatus(); + + if (status.equals(ICertRecord.STATUS_REVOKED) || + status.equals(ICertRecord.STATUS_REVOKED_EXPIRED)) { + Debug.trace("It is already revoked or Expired !!!"); + } // it is still new ... So just return this certificate to user + else { + Debug.trace("It is still new !!!"); + issuedCerts[i] = cert; + continue; + } + } + } + + // issue the cert. + issuedCerts[i] = + mService.issueX509Cert(rid, certinfos[i], true, oldSerialNo); + mService.storeX509Cert(rid, issuedCerts[i], true, oldSerialNo); + } catch (ECAException e) { + svcerrors[i] = e.toString(); + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CANNOT_RENEW", Integer.toString(i), request + .getRequestId().toString())); + } + } + + // always set issued certs regardless of error. + request.setExtData(IRequest.ISSUED_CERTS, issuedCerts); + + // set and throw error if any. + int l; + + for (l = svcerrors.length - 1; l >= 0 && svcerrors[l] == null; l--) + ; + if (l >= 0) { + request.setExtData(IRequest.SVCERRORS, svcerrors); + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_NO_RENEW", request.getRequestId().toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_RENEW_FAILED")); + } + return true; + } +} + +class getCertsForChallenge implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + + public getCertsForChallenge(CAService service) { + mService = service; + mCA = mService.getCA(); + } + + public boolean service(IRequest request) + throws EBaseException { + BigInteger[] serialNoArray = + request.getExtDataInBigIntegerArray(CAService.SERIALNO_ARRAY); + X509CertImpl[] certs = new X509CertImpl[serialNoArray.length]; + + for (int i = 0; i < serialNoArray.length; i++) { + certs[i] = mCA.getCertificateRepository().getX509Certificate(serialNoArray[i]); + } + request.setExtData(IRequest.OLD_CERTS, certs); + return true; + } +} + +class getCertStatus implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + + public getCertStatus(CAService service) { + mService = service; + mCA = mService.getCA(); + } + + public boolean service(IRequest request) throws EBaseException { + BigInteger serialno = request.getExtDataInBigInteger("serialNumber"); + String issuerDN = request.getExtDataInString("issuerDN"); + CertificateRepository certDB = (CertificateRepository) + mCA.getCertificateRepository(); + + String status = null; + + if (serialno != null) { + CertRecord record = null; + + try { + record = (CertRecord) certDB.readCertificateRecord(serialno); + } catch (EBaseException ee) { + Debug.trace(ee.toString()); + } + + if (record != null) { + status = record.getStatus(); + if (status.equals("VALID")) { + X509CertImpl cacert = mCA.getCACert(); + Principal p = cacert.getSubjectDN(); + + if (!p.toString().equals(issuerDN)) { + status = "INVALIDCERTROOT"; + } + } + } + } + + request.setExtData(IRequest.CERT_STATUS, status); + return true; + } +} + +class serviceCheckChallenge implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + private MessageDigest mSHADigest = null; + + public serviceCheckChallenge(CAService service) { + mService = service; + mCA = mService.getCA(); + try { + mSHADigest = MessageDigest.getInstance("SHA1"); + } catch (NoSuchAlgorithmException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + } + } + + public boolean service(IRequest request) + throws EBaseException { + // note: some request attributes used below are set in + // authentication/ChallengePhraseAuthentication.java :( + BigInteger serialno = request.getExtDataInBigInteger("serialNumber"); + String pwd = request.getExtDataInString( + CAService.CHALLENGE_PHRASE); + CertificateRepository certDB = (CertificateRepository) mCA.getCertificateRepository(); + BigInteger[] bigIntArray = null; + + if (serialno != null) { + CertRecord record = null; + + try { + record = (CertRecord) certDB.readCertificateRecord(serialno); + } catch (EBaseException ee) { + Debug.trace(ee.toString()); + } + if (record != null) { + String status = record.getStatus(); + + if (status.equals("VALID")) { + boolean samepwd = compareChallengePassword(record, pwd); + + if (samepwd) { + bigIntArray = new BigInteger[1]; + bigIntArray[0] = record.getSerialNumber(); + } + } else { + bigIntArray = new BigInteger[0]; + } + } else + bigIntArray = new BigInteger[0]; + } else { + String subjectName = request.getExtDataInString("subjectName"); + + if (subjectName != null) { + String filter = "(&(x509cert.subject=" + subjectName + ")(certStatus=VALID))"; + ICertRecordList list = certDB.findCertRecordsInList(filter, null, 10); + int size = list.getSize(); + Enumeration en = list.getCertRecords(0, size - 1); + + if (!en.hasMoreElements()) { + bigIntArray = new BigInteger[0]; + } else { + Vector idv = new Vector(); + + while (en.hasMoreElements()) { + ICertRecord record = en.nextElement(); + boolean samepwd = compareChallengePassword(record, pwd); + + if (samepwd) { + BigInteger id = record.getSerialNumber(); + + idv.addElement(id); + } + } + bigIntArray = new BigInteger[idv.size()]; + idv.copyInto(bigIntArray); + } + } + } + + if (bigIntArray == null) + bigIntArray = new BigInteger[0]; + + request.setExtData(CAService.SERIALNO_ARRAY, bigIntArray); + return true; + } + + private boolean compareChallengePassword(ICertRecord record, String pwd) + throws EBaseException { + MetaInfo metaInfo = (MetaInfo) record.get(CertRecord.ATTR_META_INFO); + + if (metaInfo == null) { + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_ATTRIBUTE", "metaInfo")); + } + + String hashpwd = hashPassword(pwd); + + // got metaInfo + String challengeString = + (String) metaInfo.get(CertRecord.META_CHALLENGE_PHRASE); + + if (!challengeString.equals(hashpwd)) { + return false; + } else + return true; + } + + private String hashPassword(String pwd) { + String salt = "lala123"; + byte[] pwdDigest = mSHADigest.digest((salt + pwd).getBytes()); + String b64E = Utils.base64encode(pwdDigest); + + return "{SHA}" + b64E; + } +} + +class serviceRevoke implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + + public serviceRevoke(CAService service) { + mService = service; + mCA = mService.getCA(); + } + + public boolean service(IRequest request) + throws EBaseException { + boolean sendStatus = true; + // XXX Need to think passing as array. + // XXX every implemented according to servlet. + RevokedCertImpl crlentries[] = + request.getExtDataInRevokedCertArray(IRequest.CERT_INFO); + + if (crlentries == null || + crlentries.length == 0 || + crlentries[0] == null) { + // XXX should this be an error ? + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRL_NOT_FOUND", request.getRequestId().toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_REVREQ")); + } + + RevokedCertImpl revokedCerts[] = + new RevokedCertImpl[crlentries.length]; + String svcerrors[] = null; + + for (int i = 0; i < crlentries.length; i++) { + try { + mService.revokeCert(crlentries[i], request.getRequestId().toString()); + revokedCerts[i] = crlentries[i]; + } catch (ECAException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CANNOT_REVOKE", Integer.toString(i), request + .getRequestId().toString(), e.toString())); + revokedCerts[i] = null; + if (svcerrors == null) { + svcerrors = new String[revokedCerts.length]; + } + svcerrors[i] = e.toString(); + } + } + + // #605941 - request.get(IRequest.CERT_INFO) store exact same thing + // request.set(IRequest.REVOKED_CERTS, revokedCerts); + + // if clone ca, send revoked cert records to CLA + if (CAService.mCLAConnector != null) { + CMS.debug(CMS.getLogMessage("CMSCORE_CA_CLONE_READ_REVOKED")); + BigInteger revokedCertIds[] = + new BigInteger[revokedCerts.length]; + + for (int i = 0; i < revokedCerts.length; i++) { + revokedCertIds[i] = revokedCerts[i].getSerialNumber(); + } + request.deleteExtData(IRequest.CERT_INFO); + request.deleteExtData(IRequest.OLD_CERTS); + request.setExtData(IRequest.REVOKED_CERT_RECORDS, revokedCertIds); + + CMS.debug(CMS.getLogMessage("CMSCORE_CA_CLONE_READ_REVOKED_CONNECTOR")); + + request.setRequestType(IRequest.CLA_CERT4CRL_REQUEST); + sendStatus = CAService.mCLAConnector.send(request); + if (sendStatus == false) { + request.setExtData(IRequest.RESULT, + IRequest.RES_ERROR); + request.setExtData(IRequest.ERROR, + new ECAException(CMS.getUserMessage("CMS_CA_SEND_CLA_REQUEST"))); + return sendStatus; + } else { + if (request.getExtDataInString(IRequest.ERROR) != null) { + request.setExtData(IRequest.RESULT, IRequest.RES_SUCCESS); + request.deleteExtData(IRequest.ERROR); + } + } + if (request.getExtDataInString(IRequest.ERROR) != null) { + return sendStatus; + } + } + + if (svcerrors != null) { + request.setExtData(IRequest.SVCERRORS, svcerrors); + throw new ECAException(CMS.getUserMessage("CMS_CA_REVOKE_FAILED")); + } + + if (Debug.ON) { + Debug.trace("serviceRevoke sendStatus=" + sendStatus); + } + + return sendStatus; + } +} + +class serviceUnrevoke implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + + public serviceUnrevoke(CAService service) { + mService = service; + mCA = mService.getCA(); + } + + public boolean service(IRequest request) + throws EBaseException { + boolean sendStatus = true; + BigInteger oldSerialNo[] = + request.getExtDataInBigIntegerArray(IRequest.OLD_SERIALS); + + if (oldSerialNo == null || oldSerialNo.length < 1) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_UNREVOKE_MISSING_SERIAL")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_SERIAL_NUMBER")); + } + + String svcerrors[] = null; + boolean needOldCerts = false; + X509CertImpl oldCerts[] = request.getExtDataInCertArray(IRequest.OLD_CERTS); + + if (oldCerts == null || oldCerts.length < 1) { + needOldCerts = true; + oldCerts = new X509CertImpl[oldSerialNo.length]; + } + + for (int i = 0; i < oldSerialNo.length; i++) { + try { + if (oldSerialNo[i].compareTo(new BigInteger("0")) < 0) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_UNREVOKE_MISSING_SERIAL")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_SERIAL_NUMBER")); + } + if (needOldCerts) { + CertRecord certRec = (CertRecord) + mCA.getCertificateRepository().readCertificateRecord(oldSerialNo[i]); + + oldCerts[i] = certRec.getCertificate(); + } + mService.unrevokeCert(oldSerialNo[i], request.getRequestId().toString()); + } catch (ECAException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_UNREVOKE_FAILED", oldSerialNo[i].toString(), + request.getRequestId().toString())); + if (svcerrors == null) { + svcerrors = new String[oldSerialNo.length]; + } + svcerrors[i] = e.toString(); + } + } + + // if clone ca, send unrevoked cert serials to CLA + if (CAService.mCLAConnector != null) { + request.setRequestType(IRequest.CLA_UNCERT4CRL_REQUEST); + sendStatus = CAService.mCLAConnector.send(request); + if (sendStatus == false) { + request.setExtData(IRequest.RESULT, + IRequest.RES_ERROR); + request.setExtData(IRequest.ERROR, + new ECAException(CMS.getUserMessage("CMS_CA_SEND_CLA_REQUEST"))); + return sendStatus; + } else { + if (request.getExtDataInString(IRequest.ERROR) != null) { + request.setExtData(IRequest.RESULT, IRequest.RES_SUCCESS); + request.deleteExtData(IRequest.ERROR); + } + } + + } + + if (needOldCerts) { + request.setExtData(IRequest.OLD_CERTS, oldCerts); + } + + if (svcerrors != null) { + request.setExtData(IRequest.SVCERRORS, svcerrors); + throw new ECAException(CMS.getUserMessage("CMS_CA_UNREVOKE_FAILED")); + } + + return sendStatus; + } +} + +class serviceGetCAChain implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + + public serviceGetCAChain(CAService service) { + mService = service; + mCA = mService.getCA(); + } + + public boolean service(IRequest request) throws EBaseException { + CertificateChain certChain = mCA.getCACertChain(); + ByteArrayOutputStream certChainOut = new ByteArrayOutputStream(); + try { + certChain.encode(certChainOut); + } catch (IOException e) { + mCA.log(ILogger.LL_FAILURE, e.toString()); + throw new EBaseException(e.toString()); + } + request.setExtData(IRequest.CACERTCHAIN, certChainOut.toByteArray()); + return true; + } +} + +class serviceGetCRL implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + + public serviceGetCRL(CAService service) { + mService = service; + mCA = mService.getCA(); + } + + public boolean service(IRequest request) + throws EBaseException { + try { + ICRLIssuingPointRecord crlRec = + mCA.getCRLRepository().readCRLIssuingPointRecord( + ICertificateAuthority.PROP_MASTER_CRL); + X509CRLImpl crl = new X509CRLImpl(crlRec.getCRL()); + + request.setExtData(IRequest.CRL, crl.getEncoded()); + } catch (EBaseException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_GETCRL_FIND_CRL")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_CRL_ISSUEPT_NOT_FOUND", e.toString())); + } catch (CRLException e) { + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_GETCRL_INST_CRL", ICertificateAuthority.PROP_MASTER_CRL)); + throw new ECAException( + CMS.getUserMessage("CMS_CA_CRL_ISSUEPT_NOGOOD", ICertificateAuthority.PROP_MASTER_CRL)); + } catch (X509ExtensionException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_GETCRL_NO_ISSUING_REC")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_CRL_ISSUEPT_EXT_NOGOOD", + ICertificateAuthority.PROP_MASTER_CRL)); + } + return true; + } +} + +class serviceGetRevocationInfo implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + + public serviceGetRevocationInfo(CAService service) { + mService = service; + mCA = mService.getCA(); + } + + public boolean service(IRequest request) + throws EBaseException { + Enumeration enum1 = request.getExtDataKeys(); + + while (enum1.hasMoreElements()) { + String name = enum1.nextElement(); + + if (name.equals(IRequest.ISSUED_CERTS)) { + X509CertImpl certsToCheck[] = + request.getExtDataInCertArray(IRequest.ISSUED_CERTS); + + CertificateRepository certDB = (CertificateRepository) mCA.getCertificateRepository(); + RevocationInfo info = + certDB.isCertificateRevoked(certsToCheck[0]); + + if (info != null) { + RevokedCertImpl revokedCerts[] = new RevokedCertImpl[1]; + RevokedCertImpl revokedCert = new RevokedCertImpl( + certsToCheck[0].getSerialNumber(), + info.getRevocationDate(), + info.getCRLEntryExtensions()); + + revokedCerts[0] = revokedCert; + request.setExtData(IRequest.REVOKED_CERTS, revokedCerts); + } + } + } + return true; + } +} + +class serviceGetCertificates implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + + public serviceGetCertificates(CAService service) { + mService = service; + mCA = mService.getCA(); + } + + public boolean service(IRequest request) + throws EBaseException { + Enumeration enum1 = request.getExtDataKeys(); + + while (enum1.hasMoreElements()) { + String name = enum1.nextElement(); + + if (name.equals(IRequest.CERT_FILTER)) { + String filter = request.getExtDataInString(IRequest.CERT_FILTER); + + CertificateRepository certDB = (CertificateRepository) mCA.getCertificateRepository(); + X509CertImpl[] certs = certDB.getX509Certificates(filter); + + if (certs != null) { + request.setExtData(IRequest.OLD_CERTS, certs); + } + } + } + return true; + } +} + +class serviceCert4Crl implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + + public serviceCert4Crl(CAService service) { + mService = service; + mCA = mService.getCA(); + } + + public boolean service(IRequest request) + throws EBaseException { + // XXX Need to think passing as array. + // XXX every implemented according to servlet. + BigInteger revokedCertIds[] = request.getExtDataInBigIntegerArray( + IRequest.REVOKED_CERT_RECORDS); + if (revokedCertIds == null || + revokedCertIds.length == 0) { + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CERT4CRL_NO_ENTRY", request.getRequestId().toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_CLAREQ")); + } + + CertRecord revokedCertRecs[] = new CertRecord[revokedCertIds.length]; + for (int i = 0; i < revokedCertIds.length; i++) { + revokedCertRecs[i] = (CertRecord) + mCA.getCertificateRepository().readCertificateRecord( + revokedCertIds[i]); + } + + if (revokedCertRecs == null || + revokedCertRecs.length == 0 || + revokedCertRecs[0] == null) { + // XXX should this be an error ? + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CERT4CRL_NO_ENTRY", request.getRequestId().toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_MISSING_INFO_IN_CLAREQ")); + } + + CertRecord recordedCerts[] = + new CertRecord[revokedCertRecs.length]; + String svcerrors[] = null; + + for (int i = 0; i < revokedCertRecs.length; i++) { + try { + // for CLA, record it into cert repost + ((CertificateRepository) mCA.getCertificateRepository()).addRevokedCertRecord(revokedCertRecs[i]); + // mService.revokeCert(crlentries[i]); + recordedCerts[i] = revokedCertRecs[i]; + // inform all CRLIssuingPoints about revoked certificate + Hashtable hips = mService.getCRLIssuingPoints(); + Enumeration eIPs = hips.elements(); + + while (eIPs.hasMoreElements()) { + ICRLIssuingPoint ip = eIPs.nextElement(); + // form RevokedCertImpl + RevokedCertImpl rci = + new RevokedCertImpl(revokedCertRecs[i].getSerialNumber(), + revokedCertRecs[i].getRevokedOn()); + + if (ip != null) { + ip.addRevokedCert(revokedCertRecs[i].getSerialNumber(), rci); + } + } + + } catch (ECAException e) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CERT4CRL_NO_REC", Integer.toString(i), + request.getRequestId().toString(), e.toString())); + recordedCerts[i] = null; + if (svcerrors == null) { + svcerrors = new String[recordedCerts.length]; + } + svcerrors[i] = e.toString(); + } + } + //need to record which gets recorded and which failed...cfu + // request.set(IRequest.REVOKED_CERTS, revokedCerts); + if (svcerrors != null) { + request.setExtData(IRequest.SVCERRORS, svcerrors); + throw new ECAException(CMS.getUserMessage("CMS_CA_CERT4CRL_FAILED")); + } + + return true; + } +} + +class serviceUnCert4Crl implements IServant { + private ICertificateAuthority mCA; + private CAService mService; + + public serviceUnCert4Crl(CAService service) { + mService = service; + mCA = mService.getCA(); + } + + public boolean service(IRequest request) + throws EBaseException { + BigInteger oldSerialNo[] = + request.getExtDataInBigIntegerArray(IRequest.OLD_SERIALS); + + if (oldSerialNo == null || oldSerialNo.length < 1) { + mCA.log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_UNREVOKE_MISSING_SERIAL")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_MISSING_SERIAL_NUMBER")); + } + + String svcerrors[] = null; + + for (int i = 0; i < oldSerialNo.length; i++) { + try { + mCA.getCertificateRepository().deleteCertificateRecord(oldSerialNo[i]); + // inform all CRLIssuingPoints about unrevoked certificate + Hashtable hips = mService.getCRLIssuingPoints(); + Enumeration eIPs = hips.elements(); + + while (eIPs.hasMoreElements()) { + ICRLIssuingPoint ip = eIPs.nextElement(); + + if (ip != null) { + ip.addUnrevokedCert(oldSerialNo[i]); + } + } + } catch (EBaseException e) { + mCA.log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_DELETE_CERT_ERROR", oldSerialNo[i].toString(), e.toString())); + if (svcerrors == null) { + svcerrors = new String[oldSerialNo.length]; + } + svcerrors[i] = e.toString(); + } + + } + + if (svcerrors != null) { + request.setExtData(IRequest.SVCERRORS, svcerrors); + throw new ECAException(CMS.getUserMessage("CMS_CA_UNCERT4CRL_FAILED")); + } + + return true; + } +} diff --git a/base/ca/src/com/netscape/ca/CMSCRLExtensions.java b/base/ca/src/com/netscape/ca/CMSCRLExtensions.java new file mode 100644 index 000000000..94693d69a --- /dev/null +++ b/base/ca/src/com/netscape/ca/CMSCRLExtensions.java @@ -0,0 +1,711 @@ +// --- 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.io.IOException; +import java.security.cert.CertificateException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.StringTokenizer; +import java.util.Vector; + +import netscape.security.extensions.AuthInfoAccessExtension; +import netscape.security.x509.AuthorityKeyIdentifierExtension; +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLNumberExtension; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.DeltaCRLIndicatorExtension; +import netscape.security.x509.Extension; +import netscape.security.x509.FreshestCRLExtension; +import netscape.security.x509.HoldInstructionExtension; +import netscape.security.x509.InvalidityDateExtension; +import netscape.security.x509.IssuerAlternativeNameExtension; +import netscape.security.x509.IssuingDistributionPointExtension; +import netscape.security.x509.OIDMap; +import netscape.security.x509.PKIXExtensions; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.EPropertyNotDefined; +import com.netscape.certsrv.base.EPropertyNotFound; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.ca.ICMSCRLExtension; +import com.netscape.certsrv.ca.ICMSCRLExtensions; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.common.Constants; +import com.netscape.certsrv.common.NameValuePairs; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.cms.crl.CMSIssuingDistributionPointExtension; +import com.netscape.cmscore.base.SubsystemRegistry; + +public class CMSCRLExtensions implements ICMSCRLExtensions { + public static final String PROP_ENABLE = "enable"; + public static final String PROP_EXTENSION = "extension"; + public static final String PROP_CLASS = "class"; + public static final String PROP_TYPE = "type"; + public static final String PROP_CRITICAL = "critical"; + public static final String PROP_CRL_EXT = "CRLExtension"; + public static final String PROP_CRL_ENTRY_EXT = "CRLEntryExtension"; + + private ICRLIssuingPoint mCRLIssuingPoint = null; + + private IConfigStore mConfig = null; + private IConfigStore mCRLExtConfig = null; + + private Vector mCRLExtensionNames = new Vector(); + private Vector mCRLEntryExtensionNames = new Vector(); + private Vector mEnabledCRLExtensions = new Vector(); + private Vector mCriticalCRLExtensions = new Vector(); + private Hashtable mCRLExtensionClassNames = new Hashtable(); + private Hashtable mCRLExtensionIDs = new Hashtable(); + + private static final Vector mDefaultCRLExtensionNames = new Vector(); + private static final Vector mDefaultCRLEntryExtensionNames = new Vector(); + private static final Vector mDefaultEnabledCRLExtensions = new Vector(); + private static final Vector mDefaultCriticalCRLExtensions = new Vector(); + private static final Hashtable mDefaultCRLExtensionClassNames = new Hashtable(); + private static final Hashtable mDefaultCRLExtensionIDs = new Hashtable(); + + private ILogger mLogger = CMS.getLogger(); + + static { + + /* Default CRL Extensions */ + mDefaultCRLExtensionNames.addElement(AuthorityKeyIdentifierExtension.NAME); + mDefaultCRLExtensionNames.addElement(IssuerAlternativeNameExtension.NAME); + mDefaultCRLExtensionNames.addElement(CRLNumberExtension.NAME); + mDefaultCRLExtensionNames.addElement(DeltaCRLIndicatorExtension.NAME); + mDefaultCRLExtensionNames.addElement(IssuingDistributionPointExtension.NAME); + mDefaultCRLExtensionNames.addElement(FreshestCRLExtension.NAME); + mDefaultCRLExtensionNames.addElement(AuthInfoAccessExtension.NAME2); + + /* Default CRL Entry Extensions */ + mDefaultCRLEntryExtensionNames.addElement(CRLReasonExtension.NAME); + //mDefaultCRLEntryExtensionNames.addElement(HoldInstructionExtension.NAME); + mDefaultCRLEntryExtensionNames.addElement(InvalidityDateExtension.NAME); + //mDefaultCRLEntryExtensionNames.addElement(CertificateIssuerExtension.NAME); + + /* Default Enabled CRL Extensions */ + mDefaultEnabledCRLExtensions.addElement(CRLNumberExtension.NAME); + //mDefaultEnabledCRLExtensions.addElement(DeltaCRLIndicatorExtension.NAME); + mDefaultEnabledCRLExtensions.addElement(CRLReasonExtension.NAME); + mDefaultEnabledCRLExtensions.addElement(InvalidityDateExtension.NAME); + + /* Default Critical CRL Extensions */ + mDefaultCriticalCRLExtensions.addElement(DeltaCRLIndicatorExtension.NAME); + mDefaultCriticalCRLExtensions.addElement(IssuingDistributionPointExtension.NAME); + //mDefaultCriticalCRLExtensions.addElement(CertificateIssuerExtension.NAME); + + /* CRL extension IDs */ + mDefaultCRLExtensionIDs.put(PKIXExtensions.AuthorityKey_Id.toString(), + AuthorityKeyIdentifierExtension.NAME); + mDefaultCRLExtensionIDs.put(PKIXExtensions.IssuerAlternativeName_Id.toString(), + IssuerAlternativeNameExtension.NAME); + mDefaultCRLExtensionIDs.put(PKIXExtensions.CRLNumber_Id.toString(), + CRLNumberExtension.NAME); + mDefaultCRLExtensionIDs.put(PKIXExtensions.DeltaCRLIndicator_Id.toString(), + DeltaCRLIndicatorExtension.NAME); + mDefaultCRLExtensionIDs.put(PKIXExtensions.IssuingDistributionPoint_Id.toString(), + IssuingDistributionPointExtension.NAME); + mDefaultCRLExtensionIDs.put(PKIXExtensions.ReasonCode_Id.toString(), + CRLReasonExtension.NAME); + mDefaultCRLExtensionIDs.put(PKIXExtensions.HoldInstructionCode_Id.toString(), + HoldInstructionExtension.NAME); + mDefaultCRLExtensionIDs.put(PKIXExtensions.InvalidityDate_Id.toString(), + InvalidityDateExtension.NAME); + //mDefaultCRLExtensionIDs.put(PKIXExtensions.CertificateIssuer_Id.toString(), + // CertificateIssuerExtension.NAME); + mDefaultCRLExtensionIDs.put(PKIXExtensions.FreshestCRL_Id.toString(), + FreshestCRLExtension.NAME); + mDefaultCRLExtensionIDs.put(AuthInfoAccessExtension.ID.toString(), + AuthInfoAccessExtension.NAME2); + + /* Class names */ + mDefaultCRLExtensionClassNames.put(AuthorityKeyIdentifierExtension.NAME, + "com.netscape.cms.crl.CMSAuthorityKeyIdentifierExtension"); + mDefaultCRLExtensionClassNames.put(IssuerAlternativeNameExtension.NAME, + "com.netscape.cms.crl.CMSIssuerAlternativeNameExtension"); + mDefaultCRLExtensionClassNames.put(CRLNumberExtension.NAME, + "com.netscape.cms.crl.CMSCRLNumberExtension"); + mDefaultCRLExtensionClassNames.put(DeltaCRLIndicatorExtension.NAME, + "com.netscape.cms.crl.CMSDeltaCRLIndicatorExtension"); + mDefaultCRLExtensionClassNames.put(IssuingDistributionPointExtension.NAME, + "com.netscape.cms.crl.CMSIssuingDistributionPointExtension"); + mDefaultCRLExtensionClassNames.put(CRLReasonExtension.NAME, + "com.netscape.cms.crl.CMSCRLReasonExtension"); + mDefaultCRLExtensionClassNames.put(HoldInstructionExtension.NAME, + "com.netscape.cms.crl.CMSHoldInstructionExtension"); + mDefaultCRLExtensionClassNames.put(InvalidityDateExtension.NAME, + "com.netscape.cms.crl.CMSInvalidityDateExtension"); + //mDefaultCRLExtensionClassNames.put(CertificateIssuerExtension.NAME, + // "com.netscape.cms.crl.CMSCertificateIssuerExtension"); + mDefaultCRLExtensionClassNames.put(FreshestCRLExtension.NAME, + "com.netscape.cms.crl.CMSFreshestCRLExtension"); + mDefaultCRLExtensionClassNames.put(AuthInfoAccessExtension.NAME2, + "com.netscape.cms.crl.CMSAuthInfoAccessExtension"); + + try { + OIDMap.addAttribute(DeltaCRLIndicatorExtension.class.getName(), + DeltaCRLIndicatorExtension.OID, + DeltaCRLIndicatorExtension.NAME); + } catch (CertificateException e) { + } + try { + OIDMap.addAttribute(HoldInstructionExtension.class.getName(), + HoldInstructionExtension.OID, + HoldInstructionExtension.NAME); + } catch (CertificateException e) { + } + try { + OIDMap.addAttribute(InvalidityDateExtension.class.getName(), + InvalidityDateExtension.OID, + InvalidityDateExtension.NAME); + } catch (CertificateException e) { + } + try { + OIDMap.addAttribute(FreshestCRLExtension.class.getName(), + FreshestCRLExtension.OID, + FreshestCRLExtension.NAME); + } catch (CertificateException e) { + } + } + + /** + * Constructs a CRL extensions for CRL issuing point. + */ + public CMSCRLExtensions(ICRLIssuingPoint crlIssuingPoint, IConfigStore config) { + boolean modifiedConfig = false; + + mConfig = config; + mCRLExtConfig = config.getSubStore(PROP_EXTENSION); + mCRLIssuingPoint = crlIssuingPoint; + + IConfigStore mFileConfig = + SubsystemRegistry.getInstance().get("MAIN").getConfigStore(); + + IConfigStore crlExtConfig = mFileConfig; + StringTokenizer st = new StringTokenizer(mCRLExtConfig.getName(), "."); + + while (st.hasMoreTokens()) { + String subStoreName = st.nextToken(); + IConfigStore newConfig = crlExtConfig.getSubStore(subStoreName); + + if (newConfig != null) { + crlExtConfig = newConfig; + } + } + + if (crlExtConfig != null) { + Enumeration enumExts = crlExtConfig.getSubStoreNames(); + + while (enumExts.hasMoreElements()) { + String extName = enumExts.nextElement(); + IConfigStore extConfig = crlExtConfig.getSubStore(extName); + + if (extConfig != null) { + modifiedConfig |= getEnableProperty(extName, extConfig); + modifiedConfig |= getCriticalProperty(extName, extConfig); + modifiedConfig |= getTypeProperty(extName, extConfig); + modifiedConfig |= getClassProperty(extName, extConfig); + } + } + + if (modifiedConfig) { + try { + mFileConfig.commit(true); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_SAVE_CONF", e.toString())); + } + } + } + } + + private boolean getEnableProperty(String extName, IConfigStore extConfig) { + boolean modifiedConfig = false; + + try { + if (extConfig.getBoolean(PROP_ENABLE)) { + mEnabledCRLExtensions.addElement(extName); + } + } catch (EPropertyNotFound e) { + extConfig.putBoolean(PROP_ENABLE, mDefaultEnabledCRLExtensions.contains(extName)); + modifiedConfig = true; + if (mDefaultEnabledCRLExtensions.contains(extName)) { + mEnabledCRLExtensions.addElement(extName); + } + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_NO_ENABLE", extName, + mDefaultEnabledCRLExtensions.contains(extName) ? "true" : "false")); + } catch (EPropertyNotDefined e) { + extConfig.putBoolean(PROP_ENABLE, mDefaultEnabledCRLExtensions.contains(extName)); + modifiedConfig = true; + if (mDefaultEnabledCRLExtensions.contains(extName)) { + mEnabledCRLExtensions.addElement(extName); + } + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_UNDEFINE_ENABLE", extName, + mDefaultEnabledCRLExtensions.contains(extName) ? "true" : "false")); + } catch (EBaseException e) { + extConfig.putBoolean(PROP_ENABLE, mDefaultEnabledCRLExtensions.contains(extName)); + modifiedConfig = true; + if (mDefaultEnabledCRLExtensions.contains(extName)) { + mEnabledCRLExtensions.addElement(extName); + } + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_INVALID_ENABLE", extName, + mDefaultEnabledCRLExtensions.contains(extName) ? "true" : "false")); + } + return modifiedConfig; + } + + private boolean getCriticalProperty(String extName, IConfigStore extConfig) { + boolean modifiedConfig = false; + + try { + if (extConfig.getBoolean(PROP_CRITICAL)) { + mCriticalCRLExtensions.addElement(extName); + } + } catch (EPropertyNotFound e) { + extConfig.putBoolean(PROP_CRITICAL, mDefaultCriticalCRLExtensions.contains(extName)); + modifiedConfig = true; + if (mDefaultCriticalCRLExtensions.contains(extName)) { + mCriticalCRLExtensions.addElement(extName); + } + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_NO_CRITICAL", extName, + mDefaultEnabledCRLExtensions.contains(extName) ? "true" : "false")); + } catch (EPropertyNotDefined e) { + extConfig.putBoolean(PROP_CRITICAL, mDefaultCriticalCRLExtensions.contains(extName)); + modifiedConfig = true; + if (mDefaultCriticalCRLExtensions.contains(extName)) { + mCriticalCRLExtensions.addElement(extName); + } + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_UNDEFINE_CRITICAL", extName, + mDefaultEnabledCRLExtensions.contains(extName) ? "true" : "false")); + } catch (EBaseException e) { + extConfig.putBoolean(PROP_CRITICAL, mDefaultCriticalCRLExtensions.contains(extName)); + modifiedConfig = true; + if (mDefaultCriticalCRLExtensions.contains(extName)) { + mCriticalCRLExtensions.addElement(extName); + } + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_INVALID_CRITICAL", extName, + mDefaultEnabledCRLExtensions.contains(extName) ? "true" : "false")); + } + return modifiedConfig; + } + + private boolean getTypeProperty(String extName, IConfigStore extConfig) { + boolean modifiedConfig = false; + String extType = null; + + try { + extType = extConfig.getString(PROP_TYPE); + if (extType.length() > 0) { + if (extType.equals(PROP_CRL_ENTRY_EXT)) { + mCRLEntryExtensionNames.addElement(extName); + } else if (extType.equals(PROP_CRL_EXT)) { + mCRLExtensionNames.addElement(extName); + } else { + if (mDefaultCRLEntryExtensionNames.contains(extName)) { + extConfig.putString(PROP_TYPE, PROP_CRL_ENTRY_EXT); + modifiedConfig = true; + mCRLEntryExtensionNames.addElement(extName); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_INVALID_EXT", extName, PROP_CRL_ENTRY_EXT)); + } else if (mDefaultCRLExtensionNames.contains(extName)) { + extConfig.putString(PROP_TYPE, PROP_CRL_EXT); + modifiedConfig = true; + mCRLExtensionNames.addElement(extName); + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_INVALID_EXT", extName, PROP_CRL_EXT)); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_INVALID_EXT", extName, "")); + } + } + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_UNDEFINE_EXT", extName)); + } + } catch (EPropertyNotFound e) { + if (mDefaultCRLEntryExtensionNames.contains(extName)) { + extConfig.putString(PROP_TYPE, PROP_CRL_ENTRY_EXT); + modifiedConfig = true; + } else if (mDefaultCRLExtensionNames.contains(extName)) { + extConfig.putString(PROP_TYPE, PROP_CRL_EXT); + modifiedConfig = true; + } + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_MISSING_EXT", extName)); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_INVALID_EXT", extName, "")); + } + return modifiedConfig; + } + + private boolean getClassProperty(String extName, IConfigStore extConfig) { + boolean modifiedConfig = false; + String extClass = null; + + try { + extClass = extConfig.getString(PROP_CLASS); + if (extClass.length() > 0) { + mCRLExtensionClassNames.put(extName, extClass); + + try { + @SuppressWarnings("unchecked") + Class crlExtClass = (Class) Class.forName(extClass); + + if (crlExtClass != null) { + ICMSCRLExtension cmsCRLExt = crlExtClass.newInstance(); + + if (cmsCRLExt != null) { + String id = cmsCRLExt.getCRLExtOID(); + + if (id != null) { + mCRLExtensionIDs.put(id, extName); + } + } + } + } catch (ClassCastException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_INCORRECT_CLASS", extClass, e.toString())); + } catch (ClassNotFoundException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_NOT_FOUND", extClass, e.toString())); + } catch (InstantiationException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_NOT_INST", extClass, e.toString())); + } catch (IllegalAccessException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_NOT_ACCESS", extClass, e.toString())); + } + + } else { + if (mDefaultCRLExtensionClassNames.containsKey(extName)) { + extClass = mCRLExtensionClassNames.get(extName); + extConfig.putString(PROP_CLASS, extClass); + modifiedConfig = true; + } + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_NOT_DEFINED", extName)); + } + } catch (EPropertyNotFound e) { + if (mDefaultCRLExtensionClassNames.containsKey(extName)) { + extClass = mDefaultCRLExtensionClassNames.get(extName); + extConfig.putString(PROP_CLASS, extClass); + modifiedConfig = true; + } + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_MISSING", extName)); + } catch (EBaseException e) { + if (mDefaultCRLExtensionClassNames.containsKey(extName)) { + extClass = mDefaultCRLExtensionClassNames.get(extName); + extConfig.putString(PROP_CLASS, extClass); + modifiedConfig = true; + } + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_INVALID", extName)); + } + return modifiedConfig; + } + + public boolean isCRLExtension(String extName) { + return mCRLExtensionNames.contains(extName); + } + + public boolean isCRLEntryExtension(String extName) { + return mCRLEntryExtensionNames.contains(extName); + } + + public boolean isCRLExtensionEnabled(String extName) { + return ((mCRLExtensionNames.contains(extName) || mCRLEntryExtensionNames.contains(extName)) && + mEnabledCRLExtensions.contains(extName)); + } + + public boolean isCRLExtensionCritical(String extName) { + return mCriticalCRLExtensions.contains(extName); + } + + public String getCRLExtensionName(String id) { + String name = null; + + if (mCRLExtensionIDs.containsKey(id)) { + name = mCRLExtensionIDs.get(id); + } + return name; + } + + public Vector getCRLExtensionNames() { + return new Vector(mCRLExtensionNames); + } + + public Vector getCRLEntryExtensionNames() { + return new Vector(mCRLEntryExtensionNames); + } + + public void addToCRLExtensions(CRLExtensions crlExts, String extName, Extension ext) { + if (mCRLExtensionClassNames.containsKey(extName)) { + String name = mCRLExtensionClassNames.get(extName); + + try { + @SuppressWarnings("unchecked") + Class extClass = (Class) Class.forName(name); + + if (extClass != null) { + ICMSCRLExtension cmsCRLExt = extClass.newInstance(); + + if (cmsCRLExt != null) { + if (ext != null) { + if (isCRLExtensionCritical(extName) ^ ext.isCritical()) { + ext = cmsCRLExt.setCRLExtensionCriticality( + ext, isCRLExtensionCritical(extName)); + } + } else { + ext = cmsCRLExt.getCRLExtension(mCRLExtConfig.getSubStore(extName), + mCRLIssuingPoint, + isCRLExtensionCritical(extName)); + } + + if (crlExts != null && ext != null) { + crlExts.set(extName, ext); + } + } + } + } catch (ClassCastException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_INCORRECT_CLASS", name, e.toString())); + } catch (ClassNotFoundException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_NOT_FOUND", name, e.toString())); + } catch (InstantiationException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_NOT_INST", name, e.toString())); + } catch (IllegalAccessException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_NOT_ACCESS", name, e.toString())); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_ADD", name, e.toString())); + } + } + } + + public NameValuePairs getConfigParams(String id) { + NameValuePairs nvp = null; + + if (mCRLEntryExtensionNames.contains(id) || + mCRLExtensionNames.contains(id)) { + nvp = new NameValuePairs(); + + /* + if (mCRLEntryExtensionNames.contains(id)) { + nvp.add(Constants.PR_CRLEXT_IMPL_NAME, "CRLEntryExtension"); + } else { + nvp.add(Constants.PR_CRLEXT_IMPL_NAME, "CRLExtension"); + } + + if (mCRLEntryExtensionNames.contains(id)) { + nvp.add(PROP_TYPE, "CRLEntryExtension"); + } else { + nvp.add(PROP_TYPE, "CRLExtension"); + } + */ + + if (mEnabledCRLExtensions.contains(id)) { + nvp.put(PROP_ENABLE, Constants.TRUE); + } else { + nvp.put(PROP_ENABLE, Constants.FALSE); + } + if (mCriticalCRLExtensions.contains(id)) { + nvp.put(PROP_CRITICAL, Constants.TRUE); + } else { + nvp.put(PROP_CRITICAL, Constants.FALSE); + } + + if (mCRLExtensionClassNames.containsKey(id)) { + String name = mCRLExtensionClassNames.get(id); + + if (name != null) { + + try { + Class extClass = Class.forName(name); + + if (extClass != null) { + ICMSCRLExtension cmsCRLExt = (ICMSCRLExtension) extClass.newInstance(); + + if (cmsCRLExt != null) { + cmsCRLExt.getConfigParams(mCRLExtConfig.getSubStore(id), nvp); + } + } + } catch (ClassNotFoundException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_NOT_FOUND", name, e.toString())); + } catch (InstantiationException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_NOT_INST", name, e.toString())); + } catch (IllegalAccessException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CRLEXTS_CLASS_NOT_ACCESS", name, e.toString())); + } + + int i = name.lastIndexOf('.'); + + if ((i > -1) && (i + 1 < name.length())) { + String idName = name.substring(i + 1); + + if (idName != null) { + nvp.put(Constants.PR_CRLEXT_IMPL_NAME, idName); + } + } + } + } + } + return nvp; + } + + public void setConfigParams(String id, NameValuePairs nvp, IConfigStore config) { + ICertificateAuthority ca = (ICertificateAuthority) CMS.getSubsystem(CMS.SUBSYSTEM_CA); + String ipId = nvp.get("id"); + + ICRLIssuingPoint ip = null; + if (ipId != null && ca != null) { + ip = ca.getCRLIssuingPoint(ipId); + } + + for (String name : nvp.keySet()) { + String value = nvp.get(name); + + if (name.equals(PROP_ENABLE)) { + if (!(value.equals(Constants.TRUE) || value.equals(Constants.FALSE))) { + continue; + } + if (value.equals(Constants.TRUE)) { + if (!(mEnabledCRLExtensions.contains(id))) { + mEnabledCRLExtensions.addElement(id); + } + } + if (value.equals(Constants.FALSE)) { + mEnabledCRLExtensions.remove(id); + } + } + + if (name.equals(PROP_CRITICAL)) { + if (!(value.equals(Constants.TRUE) || value.equals(Constants.FALSE))) { + continue; + } + if (value.equals(Constants.TRUE)) { + if (!(mCriticalCRLExtensions.contains(id))) { + mCriticalCRLExtensions.addElement(id); + } + } + if (value.equals(Constants.FALSE)) { + mCriticalCRLExtensions.remove(id); + } + } + //Sync the onlyContainsCACerts with similar property in CRLIssuingPoint + //called caCertsOnly. + if (name.equals(CMSIssuingDistributionPointExtension.PROP_CACERTS)) { + NameValuePairs crlIssuingPointPairs = null; + boolean crlCACertsOnly = false; + + boolean issuingDistPointExtEnabled = false; + + CMSCRLExtensions cmsCRLExtensions = (CMSCRLExtensions) ip.getCRLExtensions(); + if (cmsCRLExtensions != null) { + issuingDistPointExtEnabled = + cmsCRLExtensions.isCRLExtensionEnabled(IssuingDistributionPointExtension.NAME); + } + + CMS.debug("issuingDistPointExtEnabled = " + issuingDistPointExtEnabled); + + if (!(value.equals(Constants.TRUE) || value.equals(Constants.FALSE))) { + continue; + } + + //Get value of caCertsOnly from CRLIssuingPoint + if ((ip != null) && (issuingDistPointExtEnabled == true)) { + crlCACertsOnly = ip.isCACertsOnly(); + CMS.debug("CRLCACertsOnly is: " + crlCACertsOnly); + crlIssuingPointPairs = new NameValuePairs(); + + } + + String newValue = ""; + boolean modifiedCRLConfig = false; + //If the CRLCACertsOnly prop is false change it to true to sync. + if (value.equals(Constants.TRUE) && (issuingDistPointExtEnabled == true)) { + if (crlCACertsOnly == false) { + CMS.debug(" value = true and CRLCACertsOnly is already false."); + crlIssuingPointPairs.put(Constants.PR_CA_CERTS_ONLY, Constants.TRUE); + newValue = Constants.TRUE; + ip.updateConfig(crlIssuingPointPairs); + modifiedCRLConfig = true; + } + } + + //If the CRLCACertsOnly prop is true change it to false to sync. + if (value.equals(Constants.FALSE) && (issuingDistPointExtEnabled == true)) { + crlIssuingPointPairs.put(Constants.PR_CA_CERTS_ONLY, Constants.FALSE); + if (ip != null) { + ip.updateConfig(crlIssuingPointPairs); + newValue = Constants.FALSE; + modifiedCRLConfig = true; + } + } + + if (modifiedCRLConfig == true) { + //Commit to this CRL IssuingPoint's config store + ICertificateAuthority CA = (ICertificateAuthority) CMS.getSubsystem(CMS.SUBSYSTEM_CA); + IConfigStore crlsSubStore = CA.getConfigStore(); + crlsSubStore = crlsSubStore.getSubStore(ICertificateAuthority.PROP_CRL_SUBSTORE); + crlsSubStore = crlsSubStore.getSubStore(ipId); + try { + crlsSubStore.putString(Constants.PR_CA_CERTS_ONLY, newValue); + crlsSubStore.commit(true); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CRLEXTS_SAVE_CONF", e.toString())); + } + } + } + + config.putString(name, value); + } + } + + public String getClassPath(String name) { + Enumeration enum1 = mCRLExtensionClassNames.elements(); + + while (enum1.hasMoreElements()) { + String extClassName = enum1.nextElement(); + + if (extClassName != null) { + int i = extClassName.lastIndexOf('.'); + + if ((i > -1) && (i + 1 < extClassName.length())) { + String idName = extClassName.substring(i + 1); + + if (idName != null) { + if (name.equals(idName)) { + return extClassName; + } + } + } + } + } + + return null; + } + + private void log(int level, String msg) { + mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_CA, level, + "CMSCRLExtension - " + msg); + } +} diff --git a/base/ca/src/com/netscape/ca/CRLIssuingPoint.java b/base/ca/src/com/netscape/ca/CRLIssuingPoint.java new file mode 100644 index 000000000..d4b747b32 --- /dev/null +++ b/base/ca/src/com/netscape/ca/CRLIssuingPoint.java @@ -0,0 +1,3140 @@ +// --- 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.io.IOException; +import java.math.BigInteger; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CRLException; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.LinkedHashSet; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TimeZone; +import java.util.Vector; + +import netscape.security.util.BitArray; +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.CRLExtensions; +import netscape.security.x509.CRLNumberExtension; +import netscape.security.x509.CRLReasonExtension; +import netscape.security.x509.DeltaCRLIndicatorExtension; +import netscape.security.x509.Extension; +import netscape.security.x509.FreshestCRLExtension; +import netscape.security.x509.IssuingDistributionPoint; +import netscape.security.x509.IssuingDistributionPointExtension; +import netscape.security.x509.RevocationReason; +import netscape.security.x509.RevokedCertImpl; +import netscape.security.x509.RevokedCertificate; +import netscape.security.x509.X509CRLImpl; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509ExtensionException; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.base.SessionContext; +import com.netscape.certsrv.ca.ECAException; +import com.netscape.certsrv.ca.EErrorPublishCRL; +import com.netscape.certsrv.ca.ICMSCRLExtensions; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.common.Constants; +import com.netscape.certsrv.common.NameValuePairs; +import com.netscape.certsrv.dbs.EDBNotAvailException; +import com.netscape.certsrv.dbs.IElementProcessor; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.dbs.certdb.IRevocationInfo; +import com.netscape.certsrv.dbs.crldb.ICRLIssuingPointRecord; +import com.netscape.certsrv.dbs.crldb.ICRLRepository; +import com.netscape.certsrv.logging.AuditFormat; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.publish.ILdapRule; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.request.IRequest; +import com.netscape.certsrv.request.IRequestListener; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.IRequestVirtualList; +import com.netscape.certsrv.request.RequestId; +import com.netscape.certsrv.util.IStatsSubsystem; +import com.netscape.cmscore.dbs.CRLIssuingPointRecord; +import com.netscape.cmscore.dbs.CertRecord; +import com.netscape.cmscore.dbs.CertificateRepository; +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 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 = 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(ICertificateAuthority.PROP_CRL_SUBSTORE); + mPageSize = crlSubStore.getInteger(ICertificateAuthority.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 = list1.elementAt(i); + Vector times2 = list2.elementAt(i); + if (times1.size() != times2.size()) + identical = false; + for (int j = 0; identical && j < times1.size(); j++) { + if ((((times1.elementAt(j))).intValue()) != (((times2.elementAt(j))).intValue())) { + identical = false; + } + } + } + CMS.debug("areTimeListsIdentical: identical: " + identical); + return identical; + } + + private int getTimeListSize(Vector> listedDays) { + int listSize = 0; + for (int i = 0; listedDays != null && i < listedDays.size(); i++) { + Vector listedTimes = 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); + 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); + } + continue; + } else { + listedTimes = new Vector(); + listedDays.addElement(listedTimes); + timeListPresent = true; + } + 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); + } + + return listedDays; + } + + private String checkProfile(String id, Enumeration e) { + if (e != null) { + while (e.hasMoreElements()) { + String profileId = 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 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 (String name : params.keySet()) { + String value = params.get(name); + + // -- 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(ICertificateAuthority.PROP_CRL_SUBSTORE); + IConfigStore crlSubStore = crlsSubStore.getSubStore(mId); + IConfigStore crlExtsSubStore = + crlSubStore.getSubStore(ICertificateAuthority.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) { + @SuppressWarnings("unchecked") + Vector newProfileList = (Vector) profileList.clone(); + mProfileList = newProfileList; + } 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 { + Set certSet = new LinkedHashSet(mCRLCerts.values()); + 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 && mDailyUpdates.elementAt(0).size() == 1 && + mEnableUpdateFreq && mAutoUpdateInterval > 0) { + // Interval updates with starting time + long firstTime = MINUTE * ((Integer) 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 += mDailyUpdates.elementAt(i).size(); + } + // search the current day + for (i = 0; i < mDailyUpdates.elementAt(mCurrentDay).size(); i++) { + long t = MINUTE * ((Integer) 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 < mDailyUpdates.elementAt(mCurrentDay).size()) { + // found inside the current day + next = (MINUTE * ((Integer) 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 - 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 < mDailyUpdates.elementAt(nextDay).size()) { + if (nextDay == 0 && (!(mEnableDailyUpdates && mExtendedTimeList))) + j = 0; + t = MINUTE * ((Integer) 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 -= 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 = 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 { + mCertRepository.processRevokedCerts(p, getFilter(), mPageSize); + } + + /** + * 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 = 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 = 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, 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 = mCRLCerts.get(serialNumber).getRevocationDate(); + } + + if (checkDeltaCache && isDeltaCRLEnabled()) { + if (mUnrevokedCerts.containsKey(serialNumber)) { + revocationDate = null; + } + if (mRevokedCerts.containsKey(serialNumber)) { + revocationDate = 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(); + @SuppressWarnings("unchecked") + Hashtable clonedRevokedCerts = + (Hashtable) mRevokedCerts.clone(); + @SuppressWarnings("unchecked") + Hashtable clonedUnrevokedCerts = + (Hashtable) mUnrevokedCerts.clone(); + @SuppressWarnings("unchecked") + 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(); + @SuppressWarnings("unchecked") + Hashtable deltaCRLCerts = + (Hashtable) clonedRevokedCerts.clone(); + + deltaCRLCerts.putAll(clonedUnrevokedCerts); + if (mIncludeExpiredCertsOneExtraTime) { + if (!clonedExpiredCerts.isEmpty()) { + for (Enumeration e = clonedExpiredCerts.keys(); e.hasMoreElements();) { + BigInteger serialNumber = e.nextElement(); + if ((mLastFullUpdate != null && + mLastFullUpdate.after((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 = 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 = e.nextElement(); + + if (mCRLCerts.containsKey(serialNumber)) { + mCRLCerts.remove(serialNumber); + } + mUnrevokedCerts.remove(serialNumber); + } + } + + if (!clonedRevokedCerts.isEmpty()) { + for (Enumeration e = clonedRevokedCerts.keys(); e.hasMoreElements();) { + BigInteger serialNumber = e.nextElement(); + + mCRLCerts.put(serialNumber, mRevokedCerts.get(serialNumber)); + mRevokedCerts.remove(serialNumber); + } + } + + if (!clonedExpiredCerts.isEmpty()) { + for (Enumeration e = clonedExpiredCerts.keys(); e.hasMoreElements();) { + BigInteger serialNumber = e.nextElement(); + + if ((!mIncludeExpiredCertsOneExtraTime) || + (mLastFullUpdate != null && + mLastFullUpdate.after((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 = 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); + } + + /* + * The Session Context is a Hashtable, but without type information. + * Suppress the warnings generated by adding to the session context + * + */ + 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 = 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; + + 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, 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())); + } + } +} diff --git a/base/ca/src/com/netscape/ca/CRLWithExpiredCerts.java b/base/ca/src/com/netscape/ca/CRLWithExpiredCerts.java new file mode 100644 index 000000000..9ad619ff8 --- /dev/null +++ b/base/ca/src/com/netscape/ca/CRLWithExpiredCerts.java @@ -0,0 +1,68 @@ +// --- 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.math.BigInteger; + +import com.netscape.certsrv.base.EBaseException; +import com.netscape.cmscore.dbs.CertRecord; + +/** + * A CRL Issuing point that contains revoked certs, include onces that + * have expired. + */ +public class CRLWithExpiredCerts extends CRLIssuingPoint { + + /** + * overrides getRevokedCerts in CRLIssuingPoint to include + * all revoked certs, including once that have expired. + * + * @param thisUpdate parameter is ignored. + * + * @exception EBaseException if an exception occured getting revoked + * certificates from the database. + */ + 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 = + "(|(" + CertRecord.ATTR_CERT_STATUS + "=" + + CertRecord.STATUS_REVOKED + ")" + + "(" + CertRecord.ATTR_CERT_STATUS + "=" + + CertRecord.STATUS_REVOKED_EXPIRED + "))"; + + // 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) { + filter = "(&" + filter + ")"; + } + return filter; + } + + /** + * registers expired certificates + */ + public void addExpiredCert(BigInteger serialNumber) { + // don't do anything + } +} diff --git a/base/ca/src/com/netscape/ca/CertificateAuthority.java b/base/ca/src/com/netscape/ca/CertificateAuthority.java new file mode 100644 index 000000000..c8783f566 --- /dev/null +++ b/base/ca/src/com/netscape/ca/CertificateAuthority.java @@ -0,0 +1,2024 @@ +// --- 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.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.cert.CRLException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateParsingException; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import netscape.security.util.DerOutputStream; +import netscape.security.util.DerValue; +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.CertificateChain; +import netscape.security.x509.CertificateVersion; +import netscape.security.x509.X500Name; +import netscape.security.x509.X509CRLImpl; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509CertInfo; +import netscape.security.x509.X509ExtensionException; +import netscape.security.x509.X509Key; + +import org.mozilla.jss.CryptoManager; +import org.mozilla.jss.asn1.ASN1Util; +import org.mozilla.jss.asn1.GeneralizedTime; +import org.mozilla.jss.asn1.INTEGER; +import org.mozilla.jss.asn1.InvalidBERException; +import org.mozilla.jss.asn1.OBJECT_IDENTIFIER; +import org.mozilla.jss.asn1.OCTET_STRING; +import org.mozilla.jss.crypto.SignatureAlgorithm; +import org.mozilla.jss.crypto.TokenException; +import org.mozilla.jss.pkix.cert.Extension; +import org.mozilla.jss.pkix.primitive.Name; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.authority.ICertAuthority; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.EPropertyNotFound; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.base.Nonces; +import com.netscape.certsrv.ca.ECAException; +import com.netscape.certsrv.ca.ICRLIssuingPoint; +import com.netscape.certsrv.ca.ICertificateAuthority; +import com.netscape.certsrv.dbs.IDBSubsystem; +import com.netscape.certsrv.dbs.certdb.ICertRecord; +import com.netscape.certsrv.dbs.certdb.ICertificateRepository; +import com.netscape.certsrv.dbs.crldb.ICRLRepository; +import com.netscape.certsrv.dbs.replicadb.IReplicaIDRepository; +import com.netscape.certsrv.ldap.ELdapException; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.ocsp.IOCSPService; +import com.netscape.certsrv.policy.IPolicyProcessor; +import com.netscape.certsrv.publish.ICRLPublisher; +import com.netscape.certsrv.publish.IPublisherProcessor; +import com.netscape.certsrv.request.ARequestNotifier; +import com.netscape.certsrv.request.IPolicy; +import com.netscape.certsrv.request.IRequestListener; +import com.netscape.certsrv.request.IRequestNotifier; +import com.netscape.certsrv.request.IRequestQueue; +import com.netscape.certsrv.request.IRequestScheduler; +import com.netscape.certsrv.request.IService; +import com.netscape.certsrv.security.ISigningUnit; +import com.netscape.certsrv.util.IStatsSubsystem; +import com.netscape.cmscore.dbs.CRLRepository; +import com.netscape.cmscore.dbs.CertRecord; +import com.netscape.cmscore.dbs.CertificateRepository; +import com.netscape.cmscore.dbs.DBSubsystem; +import com.netscape.cmscore.dbs.ReplicaIDRepository; +import com.netscape.cmscore.ldap.PublisherProcessor; +import com.netscape.cmscore.listeners.ListenerPlugin; +import com.netscape.cmscore.request.RequestSubsystem; +import com.netscape.cmscore.security.KeyCertUtil; +import com.netscape.cmscore.util.Debug; +import com.netscape.cmsutil.ocsp.BasicOCSPResponse; +import com.netscape.cmsutil.ocsp.CertID; +import com.netscape.cmsutil.ocsp.CertStatus; +import com.netscape.cmsutil.ocsp.GoodInfo; +import com.netscape.cmsutil.ocsp.KeyHashID; +import com.netscape.cmsutil.ocsp.NameID; +import com.netscape.cmsutil.ocsp.OCSPRequest; +import com.netscape.cmsutil.ocsp.OCSPResponse; +import com.netscape.cmsutil.ocsp.OCSPResponseStatus; +import com.netscape.cmsutil.ocsp.ResponderID; +import com.netscape.cmsutil.ocsp.ResponseBytes; +import com.netscape.cmsutil.ocsp.ResponseData; +import com.netscape.cmsutil.ocsp.RevokedInfo; +import com.netscape.cmsutil.ocsp.SingleResponse; +import com.netscape.cmsutil.ocsp.TBSRequest; +import com.netscape.cmsutil.ocsp.UnknownInfo; + +/** + * A class represents a Certificate Authority that is + * responsible for certificate specific operations. + *

+ * + * @author lhsiao + * @version $Revision$, $Date$ + */ +public class CertificateAuthority implements ICertificateAuthority, ICertAuthority, IOCSPService { + public static final String OFFICIAL_NAME = "Certificate Manager"; + + public final static OBJECT_IDENTIFIER OCSP_NONCE = new OBJECT_IDENTIFIER("1.3.6.1.5.5.7.48.1.2"); + + protected ISubsystem mOwner = null; + protected IConfigStore mConfig = null; + protected ILogger mLogger = CMS.getLogger(); + protected Hashtable mCRLIssuePoints = new Hashtable(); + protected CRLIssuingPoint mMasterCRLIssuePoint = null; // the complete crl. + protected SigningUnit mSigningUnit; + protected SigningUnit mOCSPSigningUnit; + protected SigningUnit mCRLSigningUnit; + + protected X500Name mName = null; + protected X500Name mCRLName = null; + protected X500Name mOCSPName = null; + protected String mNickname = null; // nickname of CA signing cert. + protected String mOCSPNickname = null; // nickname of OCSP signing cert. + protected long mCertSerialNumberCounter = System.currentTimeMillis(); + protected long mRequestID = System.currentTimeMillis(); + + protected String[] mAllowedSignAlgors = null; + + protected CertificateRepository mCertRepot = null; + protected CRLRepository mCRLRepot = null; + protected ReplicaIDRepository mReplicaRepot = null; + + protected CertificateChain mCACertChain = null; + protected CertificateChain mOCSPCertChain = null; + protected X509CertImpl mCRLCert = null; + protected org.mozilla.jss.crypto.X509Certificate mCRLX509Cert = null; + protected X509CertImpl mCaCert = null; + protected org.mozilla.jss.crypto.X509Certificate mCaX509Cert = null; + protected X509CertImpl mOCSPCert = null; + protected org.mozilla.jss.crypto.X509Certificate mOCSPX509Cert = null; + protected String[] mCASigningAlgorithms = null; + + protected PublisherProcessor mPublisherProcessor = null; + protected IRequestQueue mRequestQueue = null; + protected CAPolicy mPolicy = null; + protected CAService mService = null; + protected IRequestNotifier mNotify = null; + protected IRequestNotifier mPNotify = null; + protected long mNumOCSPRequest = 0; + protected long mTotalTime = 0; + protected long mTotalData = 0; + protected long mSignTime = 0; + protected long mLookupTime = 0; + + protected static final int FASTSIGNING_DISABLED = 0; + protected static final int FASTSIGNING_ENABLED = 1; + + protected CertificateVersion mDefaultCertVersion; + protected long mDefaultValidity; + protected boolean mEnablePastCATime; + protected boolean mEnableOCSP; + protected int mFastSigning = FASTSIGNING_DISABLED; + + protected static final long SECOND = 1000; // 1000 milliseconds + protected static final long MINUTE = 60 * SECOND; + protected static final long HOUR = 60 * MINUTE; + protected static final long DAY = 24 * HOUR; + protected static final long YEAR = DAY * 365; + + protected static final String PROP_CERT_REPOS_DN = "CertificateRepositoryDN"; + protected static final String PROP_REPOS_DN = "RepositoryDN"; + protected static final String PROP_REPLICAID_DN = "dbs.replicadn"; + + // for the notification listeners + + /** + * Package constants + */ + + public IRequestListener mCertIssuedListener = null; + public IRequestListener mCertRevokedListener = null; + public IRequestListener mReqInQListener = null; + + /* cache responder ID for performance */ + private ResponderID mResponderIDByName = null; + private ResponderID mResponderIDByHash = null; + + protected Hashtable mListenerPlugins = null; + + /** + * Internal constants + */ + + protected ICRLPublisher mCRLPublisher = null; + private String mId = null; + + private boolean mByName = true; + + private boolean mUseNonces = true; + private int mMaxNonces = 100; + private Nonces mNonces = null; + + /** + * Constructs a CA subsystem. + */ + public CertificateAuthority() { + } + + /** + * Retrieves subsystem identifier. + */ + public String getId() { + return mId; + } + + public CertificateVersion getDefaultCertVersion() { + return mDefaultCertVersion; + } + + public boolean isEnablePastCATime() { + return mEnablePastCATime; + } + + /** + * Sets subsystem identifier. + */ + public void setId(String id) throws EBaseException { + mId = id; + } + + /** + * updates the Master CRL now + */ + public void updateCRLNow() throws EBaseException { + if (mMasterCRLIssuePoint != null) { + mMasterCRLIssuePoint.updateCRLNow(); + } + } + + public void publishCRLNow() throws EBaseException { + if (mMasterCRLIssuePoint != null) { + mMasterCRLIssuePoint.publishCRL(); + } + } + + public ICRLPublisher getCRLPublisher() { + return mCRLPublisher; + } + + /** + * @deprecated + */ + public IPolicyProcessor getPolicyProcessor() { + return mPolicy.getPolicyProcessor(); + } + + public boolean noncesEnabled() { + return mUseNonces; + } + + public Nonces getNonces() { + return mNonces; + } + + /** + * Initializes this CA subsystem. + *

+ * + * @param owner owner of this subsystem + * @param config configuration of this subsystem + * @exception EBaseException failed to initialize this CA + */ + public void init(ISubsystem owner, IConfigStore config) throws + EBaseException { + + try { + CMS.debug("CertificateAuthority init "); + mOwner = owner; + mConfig = config; + + // init cert & crl database. + initCaDatabases(); + + // init signing unit & CA cert. + try { + initSigUnit(); + // init default CA attributes like cert version, validity. + initDefCaAttrs(); + } catch (EBaseException e) { + if (CMS.isPreOpMode()) + ; + else + throw e; + } + + // init web gateway. + initWebGateway(); + + mUseNonces = mConfig.getBoolean("enableNonces", true); + mMaxNonces = mConfig.getInteger("maxNumberOfNonces", 100); + if (mUseNonces) { + mNonces = new Nonces(mMaxNonces); + CMS.debug("CertificateAuthority init: Nonces enabled. (" + mNonces.size() + ")"); + } + + // init request queue and related modules. + CMS.debug("CertificateAuthority init: initRequestQueue"); + initRequestQueue(); + if (CMS.isPreOpMode()) + return; + + // set certificate status to 10 minutes + mCertRepot.setCertStatusUpdateInterval( + mRequestQueue.getRequestRepository(), + mConfig.getInteger("certStatusUpdateInterval", 10 * 60), + mConfig.getBoolean("listenToCloneModifications", false)); + mCertRepot.setConsistencyCheck( + mConfig.getBoolean("ConsistencyCheck", false)); + mCertRepot.setSkipIfInConsistent( + mConfig.getBoolean("SkipIfInConsistent", false)); + + mService.init(config.getSubStore("connector")); + + initMiscellaneousListeners(); + + // instantiate CRL publisher + IConfigStore cpStore = null; + + mByName = config.getBoolean("byName", true); + + cpStore = config.getSubStore("crlPublisher"); + if (cpStore != null && cpStore.size() > 0) { + String publisherClass = cpStore.getString("class"); + + if (publisherClass != null) { + try { + @SuppressWarnings("unchecked") + Class pc = (Class) Class.forName(publisherClass); + + mCRLPublisher = pc.newInstance(); + mCRLPublisher.init(this, cpStore); + } catch (ClassNotFoundException ee) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_NO_PUBLISHER", ee.toString())); + } catch (IllegalAccessException ee) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_NO_PUBLISHER", ee.toString())); + } catch (InstantiationException ee) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_NO_PUBLISHER", ee.toString())); + } + } + } + + // initialize publisher processor (publish remote admin + // rely on this subsystem, so it has to be initialized) + initPublish(); + + // Initialize CRL issuing points. + // note CRL framework depends on DBS, CRYPTO and PUBLISHING + // being functional. + initCRL(); + + } catch (EBaseException e) { + if (CMS.isPreOpMode()) + return; + else + throw e; + } + } + + /** + * return CA's request queue processor + */ + public IRequestQueue getRequestQueue() { + return mRequestQueue; + } + + /** + * registers listener + */ + public void registerRequestListener(IRequestListener listener) { + mNotify.registerListener(listener); + } + + /** + * registers listener with a name. + */ + public void registerRequestListener(String name, IRequestListener listener) { + mNotify.registerListener(name, listener); + } + + /** + * removes listener + */ + public void removeRequestListener(IRequestListener listener) { + mNotify.removeListener(listener); + } + + /** + * removes listener with a name. + */ + public void removeRequestListener(String name) { + mNotify.removeListener(name); + } + + /** + * register listener for pending requests + */ + public void registerPendingListener(IRequestListener listener) { + mPNotify.registerListener(listener); + } + + /** + * register listener for pending requests with a name. + */ + public void registerPendingListener(String name, IRequestListener listener) { + mPNotify.registerListener(name, listener); + } + + /** + * get listener from listener list + */ + public IRequestListener getRequestListener(String name) { + return mNotify.getListener(name); + } + + /** + * get notifiers registered by CA + */ + public IRequestNotifier getRequestNotifier() { + return mNotify; + } + + /** + * get listener from listener list + */ + public IRequestListener getPendingListener(String name) { + return mPNotify.getListener(name); + } + + public Enumeration getRequestListenerNames() { + return mNotify.getListenerNames(); + } + + public IRequestListener getRequestInQListener() { + return mReqInQListener; + } + + public IRequestListener getCertIssuedListener() { + return mCertIssuedListener; + } + + public IRequestListener getCertRevokedListener() { + return mCertRevokedListener; + } + + /** + * return CA's policy processor. + */ + public IPolicy getCAPolicy() { + return mPolicy; + } + + /** + * return CA's request queue service object. + */ + public IService getCAService() { + return mService; + } + + /** + * check if the ca is a clone. + */ + public boolean isClone() { + if (CAService.mCLAConnector != null) + return true; + else + return false; + } + + /** + * Starts up this subsystem. + */ + public void startup() throws EBaseException { + if (CMS.isPreOpMode()) { + return; + } + mService.startup(); + mRequestQueue.recover(); + + // Note that this could be null. + + // setup Admin operations + + initNotificationListeners(); + + startPublish(); + // startCRL(); + } + + /** + * Shutdowns this subsystem. + *

+ */ + public void shutdown() { + Enumeration enums = mCRLIssuePoints.elements(); + while (enums.hasMoreElements()) { + CRLIssuingPoint point = (CRLIssuingPoint) enums.nextElement(); + point.shutdown(); + } + + if (mMasterCRLIssuePoint != null) { + mMasterCRLIssuePoint.shutdown(); + } + + mSigningUnit = null; + mOCSPSigningUnit = null; + mCRLSigningUnit = null; + if (mCertRepot != null) { + mCertRepot.shutdown(); + mCertRepot = null; + } + mCRLRepot = null; + mPublisherProcessor.shutdown(); + } + + /** + * Retrieves the configuration store of this subsystem. + *

+ */ + public IConfigStore getConfigStore() { + return mConfig; + } + + /** + * Retrieves logger. + */ + public ILogger getLogger() { + return CMS.getLogger(); + } + + /** + * Retrieves database services. + */ + public IDBSubsystem getDBSubsystem() { + return DBSubsystem.getInstance(); + } + + public void setValidity(String enableCAPast) throws EBaseException { + if (enableCAPast.equals("true")) + mEnablePastCATime = true; + else + mEnablePastCATime = false; + mConfig.putString(PROP_ENABLE_PAST_CATIME, enableCAPast); + } + + public long getDefaultValidity() { + return mDefaultValidity; + } + + public SignatureAlgorithm getDefaultSignatureAlgorithm() { + return mSigningUnit.getDefaultSignatureAlgorithm(); + } + + public String getDefaultAlgorithm() { + return mSigningUnit.getDefaultAlgorithm(); + } + + public void setDefaultAlgorithm(String algorithm) throws EBaseException { + mSigningUnit.setDefaultAlgorithm(algorithm); + } + + public String getStartSerial() { + try { + BigInteger serial = + mCertRepot.getTheSerialNumber(); + + if (serial == null) + return ""; + else + return serial.toString(16); + } catch (EBaseException e) { + // shouldn't get here. + return ""; + } + } + + public void setStartSerial(String serial) throws EBaseException { + mCertRepot.setTheSerialNumber(new BigInteger(serial)); + } + + public String getMaxSerial() { + String serial = mCertRepot.getMaxSerial(); + + if (serial != null) + return serial; + else + return ""; + } + + public void setMaxSerial(String serial) throws EBaseException { + mCertRepot.setMaxSerial(serial); + } + + /** + * Retrieves certificate repository. + *

+ * + * @return certificate repository + */ + public ICertificateRepository getCertificateRepository() { + return mCertRepot; + } + + /** + * Retrieves replica repository. + *

+ * + * @return replica repository + */ + public IReplicaIDRepository getReplicaRepository() { + return mReplicaRepot; + } + + /** + * Retrieves CRL repository. + */ + public ICRLRepository getCRLRepository() { + return mCRLRepot; + } + + public IPublisherProcessor getPublisherProcessor() { + return mPublisherProcessor; + } + + /** + * Retrieves the CRL issuing point by id. + *

+ * + * @param id string id of the CRL issuing point + * @return CRL issuing point + */ + public ICRLIssuingPoint getCRLIssuingPoint(String id) { + return mCRLIssuePoints.get(id); + } + + /** + * Enumerates CRL issuing points + *

+ * + * @return security service + */ + public Enumeration getCRLIssuingPoints() { + return mCRLIssuePoints.elements(); + } + + public int getCRLIssuingPointsSize() { + return mCRLIssuePoints.size(); + } + + /** + * Adds CRL issuing point with the given identifier and description. + */ + @SuppressWarnings("unchecked") + public boolean addCRLIssuingPoint(IConfigStore crlSubStore, String id, + boolean enable, String description) { + crlSubStore.makeSubStore(id); + IConfigStore c = crlSubStore.getSubStore(id); + + if (c != null) { + c.putString("allowExtensions", "true"); + c.putString("alwaysUpdate", "false"); + c.putString("autoUpdateInterval", "240"); + c.putString("caCertsOnly", "false"); + c.putString("cacheUpdateInterval", "15"); + c.putString("class", "com.netscape.ca.CRLIssuingPoint"); + c.putString("dailyUpdates", "3:45"); + c.putString("description", description); + c.putBoolean("enable", enable); + c.putString("enableCRLCache", "true"); + c.putString("enableCRLUpdates", "true"); + c.putString("enableCacheTesting", "false"); + c.putString("enableCacheRecovery", "true"); + c.putString("enableDailyUpdates", "false"); + c.putString("enableUpdateInterval", "true"); + c.putString("extendedNextUpdate", "true"); + c.putString("includeExpiredCerts", "false"); + c.putString("minUpdateInterval", "0"); + c.putString("nextUpdateGracePeriod", "0"); + c.putString("publishOnStart", "false"); + c.putString("saveMemory", "false"); + c.putString("signingAlgorithm", "SHA256withRSA"); + c.putString("updateSchema", "1"); + + // crl extensions + // AuthorityInformationAccess + c.putString("extension.AuthorityInformationAccess.enable", "false"); + c.putString("extension.AuthorityInformationAccess.critical", "false"); + c.putString("extension.AuthorityInformationAccess.type", "CRLExtension"); + c.putString("extension.AuthorityInformationAccess.class", + "com.netscape.cms.crl.CMSAuthInfoAccessExtension"); + c.putString("extension.AuthorityInformationAccess.numberOfAccessDescriptions", "1"); + c.putString("extension.AuthorityInformationAccess.accessMethod0", "caIssuers"); + c.putString("extension.AuthorityInformationAccess.accessLocationType0", "URI"); + c.putString("extension.AuthorityInformationAccess.accessLocation0", ""); + // AuthorityKeyIdentifier + c.putString("extension.AuthorityKeyIdentifier.enable", "false"); + c.putString("extension.AuthorityKeyIdentifier.critical", "false"); + c.putString("extension.AuthorityKeyIdentifier.type", "CRLExtension"); + c.putString("extension.AuthorityKeyIdentifier.class", + "com.netscape.cms.crl.CMSAuthorityKeyIdentifierExtension"); + // IssuerAlternativeName + c.putString("extension.IssuerAlternativeName.enable", "false"); + c.putString("extension.IssuerAlternativeName.critical", "false"); + c.putString("extension.IssuerAlternativeName.type", "CRLExtension"); + c.putString("extension.IssuerAlternativeName.class", + "com.netscape.cms.crl.CMSIssuerAlternativeNameExtension"); + c.putString("extension.IssuerAlternativeName.numNames", "0"); + c.putString("extension.IssuerAlternativeName.nameType0", ""); + c.putString("extension.IssuerAlternativeName.name0", ""); + // CRLNumber + c.putString("extension.CRLNumber.enable", "true"); + c.putString("extension.CRLNumber.critical", "false"); + c.putString("extension.CRLNumber.type", "CRLExtension"); + c.putString("extension.CRLNumber.class", + "com.netscape.cms.crl.CMSCRLNumberExtension"); + // DeltaCRLIndicator + c.putString("extension.DeltaCRLIndicator.enable", "false"); + c.putString("extension.DeltaCRLIndicator.critical", "true"); + c.putString("extension.DeltaCRLIndicator.type", "CRLExtension"); + c.putString("extension.DeltaCRLIndicator.class", + "com.netscape.cms.crl.CMSDeltaCRLIndicatorExtension"); + // IssuingDistributionPoint + c.putString("extension.IssuingDistributionPoint.enable", "false"); + c.putString("extension.IssuingDistributionPoint.critical", "true"); + c.putString("extension.IssuingDistributionPoint.type", "CRLExtension"); + c.putString("extension.IssuingDistributionPoint.class", + "com.netscape.cms.crl.CMSIssuingDistributionPointExtension"); + c.putString("extension.IssuingDistributionPoint.pointType", ""); + c.putString("extension.IssuingDistributionPoint.pointName", ""); + c.putString("extension.IssuingDistributionPoint.onlyContainsUserCerts", "false"); + c.putString("extension.IssuingDistributionPoint.onlyContainsCACerts", "false"); + c.putString("extension.IssuingDistributionPoint.onlySomeReasons", ""); + //"keyCompromise,cACompromise,affiliationChanged,superseded,cessationOfOperation,certificateHold"); + c.putString("extension.IssuingDistributionPoint.indirectCRL", "false"); + // CRLReason + c.putString("extension.CRLReason.enable", "true"); + c.putString("extension.CRLReason.critical", "false"); + c.putString("extension.CRLReason.type", "CRLEntryExtension"); + c.putString("extension.CRLReason.class", + "com.netscape.cms.crl.CMSCRLReasonExtension"); + // HoldInstruction - removed by RFC 5280 + // c.putString("extension.HoldInstruction.enable", "false"); + // c.putString("extension.HoldInstruction.critical", "false"); + // c.putString("extension.HoldInstruction.type", "CRLEntryExtension"); + // c.putString("extension.HoldInstruction.class", + // "com.netscape.cms.crl.CMSHoldInstructionExtension"); + // c.putString("extension.HoldInstruction.instruction", "none"); + // InvalidityDate + c.putString("extension.InvalidityDate.enable", "true"); + c.putString("extension.InvalidityDate.critical", "false"); + c.putString("extension.InvalidityDate.type", "CRLEntryExtension"); + c.putString("extension.InvalidityDate.class", + "com.netscape.cms.crl.CMSInvalidityDateExtension"); + // CertificateIssuer + /* + c.putString("extension.CertificateIssuer.enable", "false"); + c.putString("extension.CertificateIssuer.critical", "true"); + c.putString("extension.CertificateIssuer.type", "CRLEntryExtension"); + c.putString("extension.CertificateIssuer.class", + "com.netscape.cms.crl.CMSCertificateIssuerExtension"); + c.putString("extension.CertificateIssuer.numNames", "0"); + c.putString("extension.CertificateIssuer.nameType0", ""); + c.putString("extension.CertificateIssuer.name0", ""); + */ + // FreshestCRL + c.putString("extension.FreshestCRL.enable", "false"); + c.putString("extension.FreshestCRL.critical", "false"); + c.putString("extension.FreshestCRL.type", "CRLExtension"); + c.putString("extension.FreshestCRL.class", + "com.netscape.cms.crl.CMSFreshestCRLExtension"); + c.putString("extension.FreshestCRL.numPoints", "0"); + c.putString("extension.FreshestCRL.pointType0", ""); + c.putString("extension.FreshestCRL.pointName0", ""); + + String issuingPointClassName = null; + Class issuingPointClass = null; + CRLIssuingPoint issuingPoint = null; + + try { + issuingPointClassName = c.getString(PROP_CLASS); + issuingPointClass = (Class) Class.forName(issuingPointClassName); + issuingPoint = (CRLIssuingPoint) issuingPointClass.newInstance(); + issuingPoint.init(this, id, c); + mCRLIssuePoints.put(id, issuingPoint); + } catch (EPropertyNotFound e) { + crlSubStore.removeSubStore(id); + return false; + } catch (EBaseException e) { + crlSubStore.removeSubStore(id); + return false; + } catch (ClassNotFoundException e) { + crlSubStore.removeSubStore(id); + return false; + } catch (InstantiationException e) { + crlSubStore.removeSubStore(id); + return false; + } catch (IllegalAccessException e) { + crlSubStore.removeSubStore(id); + return false; + } + } + return true; + } + + /** + * Deletes CRL issuing point with the given identifier. + */ + public void deleteCRLIssuingPoint(IConfigStore crlSubStore, String id) { + CRLIssuingPoint ip = (CRLIssuingPoint) mCRLIssuePoints.get(id); + + if (ip != null) { + ip.shutdown(); + mCRLIssuePoints.remove(id); + ip = null; + crlSubStore.removeSubStore(id); + try { + mCRLRepot.deleteCRLIssuingPointRecord(id); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("FAILED_REMOVING_CRL_IP_2", id, e.toString())); + } + } + } + + /** + * Returns X500 name of the Certificate Authority + *

+ * + * @return CA name + */ + public X500Name getX500Name() { + return mName; + } + + public X500Name getCRLX500Name() { + return mCRLName; + } + + public X500Name getOCSPX500Name() { + return mOCSPName; + } + + /** + * Returns nickname of CA's signing cert. + *

+ * + * @return CA signing cert nickname. + */ + public String getNickname() { + return mNickname; + } + + /** + * Returns nickname of OCSP's signing cert. + *

+ * + * @return OCSP signing cert nickname. + */ + public String getOCSPNickname() { + return mOCSPNickname; + } + + /** + * Returns default signing unit used by this CA + *

+ * + * @return request identifier + */ + public ISigningUnit getSigningUnit() { + return mSigningUnit; + } + + public ISigningUnit getCRLSigningUnit() { + return mCRLSigningUnit; + } + + public ISigningUnit getOCSPSigningUnit() { + return mOCSPSigningUnit; + } + + public void setBasicConstraintMaxLen(int num) { + mConfig.putString("Policy.rule.BasicConstraintsExt.maxPathLen", "" + num); + } + + /** + * Signs CRL using the specified signature algorithm. + * If no algorithm is specified the CA's default signing algorithm + * is used. + *

+ * + * @param crl the CRL to be signed. + * @param algname the algorithm name to use. This is a JCA name such + * as MD5withRSA, etc. If set to null the default signing algorithm + * is used. + * + * @return the signed CRL + */ + public X509CRLImpl sign(X509CRLImpl crl, String algname) + throws EBaseException { + X509CRLImpl signedcrl = null; + + IStatsSubsystem statsSub = (IStatsSubsystem) CMS.getSubsystem("stats"); + if (statsSub != null) { + statsSub.startTiming("signing"); + } + + try { + DerOutputStream out = new DerOutputStream(); + DerOutputStream tmp = new DerOutputStream(); + + if (algname == null) { + algname = mSigningUnit.getDefaultAlgorithm(); + } + + crl.encodeInfo(tmp); + AlgorithmId.get(algname).encode(tmp); + + byte[] tbsCertList = crl.getTBSCertList(); + + byte[] signature = mCRLSigningUnit.sign(tbsCertList, algname); + + if (crl.setSignature(signature)) { + tmp.putBitString(signature); + out.write(DerValue.tag_Sequence, tmp); + + if (crl.setSignedCRL(out.toByteArray())) { + signedcrl = crl; + // signedcrl = new X509CRLImpl(out.toByteArray()); + } else { + CMS.debug("Failed to add signed-CRL to CRL object."); + } + } else { + CMS.debug("Failed to add signature to CRL object."); + } + } catch (CRLException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_SIGN_CRL", e.toString(), e.getMessage())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_CRL_FAILED", e.getMessage())); + } catch (X509ExtensionException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_SIGN_CRL", e.toString(), e.getMessage())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_CRL_FAILED", e.getMessage())); + } catch (NoSuchAlgorithmException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_SIGN_CRL", e.toString(), e.getMessage())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_CRL_FAILED", e.getMessage())); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_SIGN_CRL", e.toString(), e.getMessage())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_CRL_FAILED", e.getMessage())); + } finally { + if (statsSub != null) { + statsSub.endTiming("signing"); + } + } + + return signedcrl; + } + + /** + * Signs the given certificate info using specified signing algorithm + * If no algorithm is specified the CA's default algorithm is used. + *

+ * + * @param certInfo the certificate info to be signed. + * @param algname the signing algorithm to use. These are names defined + * in JCA, such as MD5withRSA, etc. If null the CA's default + * signing algorithm will be used. + * @return signed certificate + */ + public X509CertImpl sign(X509CertInfo certInfo, String algname) + throws EBaseException { + + X509CertImpl signedcert = null; + + IStatsSubsystem statsSub = (IStatsSubsystem) CMS.getSubsystem("stats"); + if (statsSub != null) { + statsSub.startTiming("signing"); + } + + try { + DerOutputStream out = new DerOutputStream(); + DerOutputStream tmp = new DerOutputStream(); + + if (certInfo == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_NO_CERTINFO")); + return null; + } + + if (algname == null) { + algname = mSigningUnit.getDefaultAlgorithm(); + } + + CMS.debug("sign cert get algorithm"); + AlgorithmId alg = AlgorithmId.get(algname); + + // encode certificate info + CMS.debug("sign cert encoding cert"); + certInfo.encode(tmp); + byte[] rawCert = tmp.toByteArray(); + + // encode algorithm identifier + CMS.debug("sign cert encoding algorithm"); + alg.encode(tmp); + + CMS.debug("CA cert signing: signing cert"); + byte[] signature = mSigningUnit.sign(rawCert, algname); + + tmp.putBitString(signature); + + // Wrap the signed data in a SEQUENCE { data, algorithm, sig } + out.write(DerValue.tag_Sequence, tmp); + //log(ILogger.LL_INFO, "CertificateAuthority: done signing"); + + switch (mFastSigning) { + case FASTSIGNING_DISABLED: + signedcert = new X509CertImpl(out.toByteArray()); + break; + + case FASTSIGNING_ENABLED: + signedcert = new X509CertImpl(out.toByteArray(), certInfo); + break; + + default: + break; + } + } catch (NoSuchAlgorithmException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_SIGN_CERT", e.toString(), e.getMessage())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_CERT_FAILED", e.getMessage())); + } catch (IOException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_SIGN_CERT", e.toString(), e.getMessage())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_CERT_FAILED", e.getMessage())); + } catch (CertificateException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_SIGN_CERT", e.toString(), e.getMessage())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_CERT_FAILED", e.getMessage())); + } finally { + if (statsSub != null) { + statsSub.endTiming("signing"); + } + } + return signedcert; + } + + /** + * Sign a byte array using the specified algorithm. + * If algorithm is null the CA's default algorithm is used. + *

+ * + * @param data the data to be signed in a byte array. + * @param algname the algorithm to use. + * @return the signature in a byte array. + */ + public byte[] sign(byte[] data, String algname) + throws EBaseException { + return mSigningUnit.sign(data, algname); + } + + /** + * logs a message in the CA area. + * + * @param level the debug level. + * @param msg the message to debug. + */ + public void log(int level, String msg) { + mLogger.log(ILogger.EV_SYSTEM, ILogger.S_CA, + level, msg); + } + + /** + * Retrieves certificate chains of this CA. + * + * @return this CA's cert chain. + */ + public CertificateChain getCACertChain() { + return mCACertChain; + } + + public X509CertImpl getCACert() { + if (mCaCert != null) { + return mCaCert; + } + // during configuration + try { + String cert = mConfig.getString("signing.cert", null); + if (cert != null) { + return new X509CertImpl(CMS.AtoB(cert)); + } + } catch (EBaseException e) { + CMS.debug(e); + } catch (CertificateException e) { + CMS.debug(e); + } + return null; + } + + public org.mozilla.jss.crypto.X509Certificate getCaX509Cert() { + return mCaX509Cert; + } + + public String[] getCASigningAlgorithms() { + if (mCASigningAlgorithms != null) + return mCASigningAlgorithms; + + if (mCaCert == null) + return null; // CA not inited yet. + X509Key caPubKey = null; + + try { + caPubKey = (X509Key) mCaCert.get(X509CertImpl.PUBLIC_KEY); + } catch (CertificateParsingException e) { + } + if (caPubKey == null) + return null; // something seriously wrong. + AlgorithmId alg = caPubKey.getAlgorithmId(); + + if (alg == null) + return null; // something seriously wrong. + mCASigningAlgorithms = AlgorithmId.getSigningAlgorithms(alg); + if (mCASigningAlgorithms == null) { + CMS.debug( + "CA - no signing algorithms for " + alg.getName()); + } else { + CMS.debug( + "CA First signing algorithm is " + mCASigningAlgorithms[0]); + } + + return mCASigningAlgorithms; + } + + ////////// + // Initialization routines. + // + + /** + * init CA signing unit & cert chain. + */ + private void initSigUnit() + throws EBaseException { + try { + // init signing unit + mSigningUnit = new SigningUnit(); + IConfigStore caSigningCfg = + mConfig.getSubStore(PROP_SIGNING_SUBSTORE); + + mSigningUnit.init(this, caSigningCfg); + CMS.debug("CA signing unit inited"); + + // for identrus + IConfigStore CrlStore = mConfig.getSubStore(PROP_CRL_SIGNING_SUBSTORE); + + if (CrlStore != null && CrlStore.size() > 0) { + mCRLSigningUnit = new SigningUnit(); + mCRLSigningUnit.init(this, mConfig.getSubStore(PROP_CRL_SIGNING_SUBSTORE)); + } else { + mCRLSigningUnit = mSigningUnit; + } + + // init cert chain + CryptoManager manager = CryptoManager.getInstance(); + + int caChainNum = + caSigningCfg.getInteger(PROP_CA_CHAIN_NUM, 0); + + CMS.debug("cachainNum= " + caChainNum); + if (caChainNum > 0) { + // custom build chain (for cross cert chain) + // audit here *** + IConfigStore chainStore = + caSigningCfg.getSubStore(PROP_CA_CHAIN); + + if (chainStore == null) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CA_OCSP_CHAIN", + "ca cert chain config error")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_BUILD_CA_CHAIN_FAILED", + "ca cert chain config error")); + } + + java.security.cert.X509Certificate[] implchain = + new java.security.cert.X509Certificate[caChainNum]; + + for (int i = 0; i < caChainNum; i++) { + String subtreeName = PROP_CA_CERT + i; + // cert file name must be full path + String certFileName = + chainStore.getString(subtreeName, null); + + if ((certFileName == null) || certFileName.equals("")) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_OCSP_CHAIN", "cert file config error")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_BUILD_CA_CHAIN_FAILED", + "cert file config error")); + } + byte[] b64Bytes = getCertFromFile(certFileName); + String b64String = new String(b64Bytes); + byte[] certBytes = KeyCertUtil.convertB64EToByteArray(b64String); + + implchain[i] = new X509CertImpl(certBytes); + } // for + + mCACertChain = new CertificateChain(implchain); + CMS.debug("in init - custom built CA cert chain."); + } else { + // build ca chain the traditional way + org.mozilla.jss.crypto.X509Certificate[] chain = + manager.buildCertificateChain(mSigningUnit.getCert()); + // do this in case other subsyss expect a X509CertImpl + java.security.cert.X509Certificate[] implchain = + new java.security.cert.X509Certificate[chain.length]; + + for (int i = 0; i < chain.length; i++) { + implchain[i] = new X509CertImpl(chain[i].getEncoded()); + } + mCACertChain = new CertificateChain(implchain); + CMS.debug("in init - got CA chain from JSS."); + } + + IConfigStore OCSPStore = mConfig.getSubStore(PROP_OCSP_SIGNING_SUBSTORE); + + if (OCSPStore != null && OCSPStore.size() > 0) { + mOCSPSigningUnit = new SigningUnit(); + mOCSPSigningUnit.init(this, mConfig.getSubStore(PROP_OCSP_SIGNING_SUBSTORE)); + CMS.debug("Separate OCSP signing unit inited"); + } else { + mOCSPSigningUnit = mSigningUnit; + CMS.debug("Shared OCSP signing unit inited"); + } + + org.mozilla.jss.crypto.X509Certificate[] ocspChain = + manager.buildCertificateChain(mOCSPSigningUnit.getCert()); + // do this in case other subsyss expect a X509CertImpl + java.security.cert.X509Certificate[] ocspImplchain = + new java.security.cert.X509Certificate[ocspChain.length]; + + for (int i = 0; i < ocspChain.length; i++) { + ocspImplchain[i] = new X509CertImpl(ocspChain[i].getEncoded()); + } + mOCSPCertChain = new CertificateChain(ocspImplchain); + CMS.debug("in init - got OCSP chain from JSS."); + // init issuer name - take name from the cert. + + mCaX509Cert = mSigningUnit.getCert(); + mCaCert = new X509CertImpl(mCaX509Cert.getEncoded()); + getCASigningAlgorithms(); + mName = (X500Name) mCaCert.getSubjectDN(); + + mCRLX509Cert = mCRLSigningUnit.getCert(); + mCRLCert = new X509CertImpl(mCRLX509Cert.getEncoded()); + mCRLName = (X500Name) mCRLCert.getSubjectDN(); + + mOCSPX509Cert = mOCSPSigningUnit.getCert(); + mOCSPNickname = mOCSPSigningUnit.getNickname(); + mOCSPCert = new X509CertImpl(mOCSPX509Cert.getEncoded()); + mOCSPName = (X500Name) mOCSPCert.getSubjectDN(); + mNickname = mSigningUnit.getNickname(); + CMS.debug("in init - got CA name " + mName); + + } catch (CryptoManager.NotInitializedException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_OCSP_SIGNING", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_CRYPTO_NOT_INITIALIZED")); + } catch (CertificateException e) { + if (Debug.ON) + e.printStackTrace(); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_OCSP_CHAIN", e.toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_BUILD_CA_CHAIN_FAILED", e.toString())); + } catch (FileNotFoundException e) { + if (Debug.ON) + e.printStackTrace(); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_OCSP_CHAIN", e.toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_BUILD_CA_CHAIN_FAILED", e.toString())); + } catch (IOException e) { + if (Debug.ON) + e.printStackTrace(); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_OCSP_CHAIN", e.toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_BUILD_CA_CHAIN_FAILED", e.toString())); + } catch (TokenException e) { + if (Debug.ON) + e.printStackTrace(); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_OCSP_CHAIN", e.toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_BUILD_CA_CHAIN_FAILED", e.toString())); + } + } + + /** + * read ca cert from path, converts and bytes + */ + byte[] getCertFromFile(String path) + throws FileNotFoundException, IOException { + + File file = new File(path); + Long l = Long.valueOf(file.length()); + byte[] b = new byte[l.intValue()]; + FileInputStream in = new FileInputStream(path); + in.read(b); + in.close(); + + return b; + } + + /** + * init default cert attributes. + */ + private void initDefCaAttrs() + throws EBaseException { + int version = mConfig.getInteger(PROP_X509CERT_VERSION, + CertificateVersion.V3); + + if (version != CertificateVersion.V1 && + version != CertificateVersion.V3) { + throw new ECAException( + CMS.getUserMessage("CMS_CA_X509CERT_VERSION_NOT_SUPPORTED")); + } + try { + mDefaultCertVersion = new CertificateVersion(version - 1); + } catch (IOException e) { + // should never occur. + } + + int validity_in_days = mConfig.getInteger(PROP_DEF_VALIDITY, 2 * 365); + + mDefaultValidity = validity_in_days * DAY; // days in config file. + + mEnablePastCATime = + mConfig.getBoolean(PROP_ENABLE_PAST_CATIME, false); + mEnableOCSP = + mConfig.getBoolean(PROP_ENABLE_OCSP, true); + + String fs = mConfig.getString(PROP_FAST_SIGNING, ""); + + if (fs.equals("enabled") || fs.equals("enable")) { + mFastSigning = FASTSIGNING_ENABLED; + } else { + mFastSigning = FASTSIGNING_DISABLED; + } + + } + + /** + * init cert & crl database + */ + private void initCaDatabases() + throws EBaseException { + int certdb_inc = mConfig.getInteger(PROP_CERTDB_INC, 5); + + String certReposDN = mConfig.getString(PROP_CERT_REPOS_DN, null); + + if (certReposDN == null) { + certReposDN = "ou=certificateRepository, ou=" + getId() + + ", " + getDBSubsystem().getBaseDN(); + } + String reposDN = mConfig.getString(PROP_REPOS_DN, null); + + if (reposDN == null) { + reposDN = "ou=certificateRepository, ou=" + getId() + + ", " + getDBSubsystem().getBaseDN(); + } + + int transitMaxRecords = mConfig.getInteger(PROP_CERTDB_TRANS_MAXRECORDS, 1000000); + int transitRecordPageSize = mConfig.getInteger(PROP_CERTDB_TRANS_PAGESIZE, 200); + + mCertRepot = new CertificateRepository( + DBSubsystem.getInstance(), + certReposDN, certdb_inc, reposDN); + + mCertRepot.setTransitMaxRecords(transitMaxRecords); + mCertRepot.setTransitRecordPageSize(transitRecordPageSize); + + CMS.debug("Cert Repot inited"); + + // init crl repot. + + int crldb_inc = mConfig.getInteger(PROP_CRLDB_INC, 5); + + mCRLRepot = new CRLRepository( + DBSubsystem.getInstance(), + crldb_inc, + "ou=crlIssuingPoints, ou=" + getId() + ", " + + getDBSubsystem().getBaseDN()); + CMS.debug("CRL Repot inited"); + + String replicaReposDN = mConfig.getString(PROP_REPLICAID_DN, null); + if (replicaReposDN == null) { + replicaReposDN = "ou=Replica," + getDBSubsystem().getBaseDN(); + } + mReplicaRepot = new ReplicaIDRepository( + DBSubsystem.getInstance(), 1, replicaReposDN); + CMS.debug("Replica Repot inited"); + + } + + /** + * init web gateway - just gets the ee gateway for this CA. + */ + private void initWebGateway() + throws EBaseException { + } + + private void startPublish() + throws EBaseException { + //xxx Note that CMS411 only support ca cert publishing to ldap + // if ldap publishing is not enabled while publishing isenabled + // there will be a lot of problem. + try { + if (mPublisherProcessor.enabled()) { + mPublisherProcessor.publishCACert(mCaCert); + CMS.debug("published ca cert"); + } + } catch (ELdapException e) { + // exception not thrown - not seen as a fatal error. + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_PUBLISH", e.toString())); + } + } + + /** + * init publishing + */ + private void initPublish() + throws EBaseException { + IConfigStore c = null; + + try { + c = mConfig.getSubStore(PROP_PUBLISH_SUBSTORE); + if (c != null && c.size() > 0) { + mPublisherProcessor = new PublisherProcessor( + getId() + "pp"); + mPublisherProcessor.init(this, c); + CMS.debug("Publishing inited"); + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_NO_PUBLISH")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_INIT_PUBLISH_MODULE_FAILED")); + } + + } catch (ELdapException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_ERROR_PUBLISH_MODULE", e.toString())); + //throw new ECAException( + // CAResources.INIT_PUBLISH_MODULE_FAILED, e); + } + } + + private void initMiscellaneousListeners() { + IConfigStore lc = null; + IConfigStore implc = null; + IConfigStore instc = null; + + mListenerPlugins = new Hashtable(); + try { + // Get list of listener implementations + lc = mConfig.getSubStore(PROP_LISTENER_SUBSTORE); + if (lc != null) { + + implc = lc.getSubStore(PROP_IMPL); + Enumeration names = implc.getSubStoreNames(); + + while (names.hasMoreElements()) { + String id = names.nextElement(); + + if (Debug.ON) + Debug.trace("registering listener impl: " + id); + String cl = implc.getString(id + "." + PROP_CLASS); + + ListenerPlugin plugin = new ListenerPlugin(id, cl); + + mListenerPlugins.put(id, plugin); + } + + instc = lc.getSubStore(PROP_INSTANCE); + Enumeration instances = instc.getSubStoreNames(); + + while (instances.hasMoreElements()) { + String id = (String) instances.nextElement(); + + if (Debug.ON) + Debug.trace("registering listener instance: " + id); + IConfigStore iConfig = instc.getSubStore(id); + String implName = instc.getString(id + "." + PROP_PLUGIN); + ListenerPlugin plugin = (ListenerPlugin) mListenerPlugins.get(implName); + + if (plugin == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_ERROR_LISTENER", implName)); + throw new Exception("Cannot initialize"); + } + String className = plugin.getClassPath(); + + try { + IRequestListener listener = null; + + listener = (IRequestListener) + Class.forName(className).newInstance(); + + //listener.init(id, implName, iConfig); + listener.init(this, iConfig); + // registerRequestListener(id, (IRequestListener) listener); + //log(ILogger.LL_INFO, + // "Listener instance " + id + " added"); + + } catch (Exception e) { + if (Debug.ON) { + e.printStackTrace(); + } + Debug.trace("failed to add listener instance"); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_INIT_LISTENER", id, e.toString())); + throw e; + } + } + + } + + } catch (Exception e) { + log(ILogger.LL_INFO, CMS.getLogMessage("CMSCORE_CA_CA_FAILED_LISTENER", e.toString())); + } + + } + + /** + * init notification related listeners + */ + private void initNotificationListeners() { + IConfigStore nc = null; + + try { + nc = mConfig.getSubStore(PROP_NOTIFY_SUBSTORE); + if (nc != null && nc.size() > 0) { + // Initialize Certificate Issued notification listener + + String certificateIssuedListenerClassName = + nc.getString("certificateIssuedListenerClassName", + "com.netscape.cms.listeners.CertificateIssuedListener"); + + try { + mCertIssuedListener = + (IRequestListener) Class.forName(certificateIssuedListenerClassName).newInstance(); + mCertIssuedListener.init(this, nc); + } catch (Exception e1) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CA_REGISTER_LISTENER", certificateIssuedListenerClassName)); + } + + // Initialize Revoke Request notification listener + + String certificateRevokedListenerClassName = + nc.getString("certificateIssuedListenerClassName", + "com.netscape.cms.listeners.CertificateRevokedListener"); + + try { + mCertRevokedListener = + (IRequestListener) Class.forName(certificateRevokedListenerClassName).newInstance(); + mCertRevokedListener.init(this, nc); + } catch (Exception e1) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CA_REGISTER_LISTENER", certificateRevokedListenerClassName)); + } + + // Initialize Request In Queue notification listener + String requestInQListenerClassName = + nc.getString("certificateIssuedListenerClassName", + "com.netscape.cms.listeners.RequestInQListener"); + + try { + mReqInQListener = (IRequestListener) Class.forName(requestInQListenerClassName).newInstance(); + mReqInQListener.init(this, nc); + } catch (Exception e1) { + log(ILogger.LL_FAILURE, + CMS.getLogMessage("CMSCORE_CA_CA_REGISTER_REQ_LISTENER", requestInQListenerClassName)); + } + + } else { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_NOTIFY_NONE")); + } + } catch (Exception e) { + e.printStackTrace(); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_NOTIFY_FAILED")); + // throw e; + } + } + + /** + * initialize request queue components + */ + private void initRequestQueue() + throws EBaseException { + mPolicy = new CAPolicy(); + ((CAPolicy) mPolicy).init(this, mConfig.getSubStore(PROP_POLICY)); + CMS.debug("CA policy inited"); + mService = new CAService(this); + CMS.debug("CA service inited"); + + mNotify = new ARequestNotifier(this); + CMS.debug("CA notifier inited"); + mPNotify = new ARequestNotifier(); + CMS.debug("CA pending notifier inited"); + + // instantiate CA request queue. + try { + int reqdb_inc = mConfig.getInteger("reqdbInc", 5); + + mRequestQueue = + RequestSubsystem.getInstance().getRequestQueue( + getId(), reqdb_inc, mPolicy, mService, mNotify, mPNotify); + } catch (EBaseException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_QUEUE_FAILED", e.toString())); + throw e; + } + + // init request scheduler if configured + String schedulerClass = + mConfig.getString("requestSchedulerClass", null); + + if (schedulerClass != null) { + try { + IRequestScheduler scheduler = (IRequestScheduler) + Class.forName(schedulerClass).newInstance(); + + mRequestQueue.setRequestScheduler(scheduler); + } catch (Exception e) { + // do nothing here + } + } + } + + /* + private void startCRL() + throws EBaseException + { + Enumeration e = mCRLIssuePoints.keys(); + while (e.hasMoreElements()) { + CRLIssuingPoint cp = (CRLIssuingPoint) + mCRLIssuePoints.get(e.nextElement()); + cp.startup(); + } + } + */ + + /** + * initialize CRL + */ + @SuppressWarnings("unchecked") + private void initCRL() + throws EBaseException { + IConfigStore crlConfig = mConfig.getSubStore(PROP_CRL_SUBSTORE); + + if ((crlConfig == null) || (crlConfig.size() <= 0)) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_NO_MASTER_CRL")); + //throw new ECAException(CAResources.NO_CONFIG_FOR_MASTER_CRL); + return; + } + Enumeration issuePointIdEnum = crlConfig.getSubStoreNames(); + + if (issuePointIdEnum == null || !issuePointIdEnum.hasMoreElements()) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_NO_MASTER_CRL_SUBSTORE")); + //throw new ECAException(CAResources.NO_CONFIG_FOR_MASTER_CRL); + return; + } + + // a Master/full crl must exist. + + while (issuePointIdEnum.hasMoreElements()) { + String issuePointId = issuePointIdEnum.nextElement(); + + CMS.debug( + "initializing crl issue point " + issuePointId); + IConfigStore issuePointConfig = null; + String issuePointClassName = null; + Class issuePointClass = null; + CRLIssuingPoint issuePoint = null; + + try { + issuePointConfig = crlConfig.getSubStore(issuePointId); + issuePointClassName = issuePointConfig.getString(PROP_CLASS); + issuePointClass = (Class) Class.forName(issuePointClassName); + issuePoint = issuePointClass.newInstance(); + issuePoint.init(this, issuePointId, issuePointConfig); + mCRLIssuePoints.put(issuePointId, issuePoint); + if (mMasterCRLIssuePoint == null && + issuePointId.equals(PROP_MASTER_CRL)) + mMasterCRLIssuePoint = issuePoint; + } catch (ClassNotFoundException e) { + throw new ECAException( + CMS.getUserMessage("CMS_CA_CRL_ISSUING_POINT_INIT_FAILED", + issuePointId, e.toString())); + } catch (InstantiationException e) { + throw new ECAException( + CMS.getUserMessage("CMS_CA_CRL_ISSUING_POINT_INIT_FAILED", + issuePointId, e.toString())); + } catch (IllegalAccessException e) { + throw new ECAException( + CMS.getUserMessage("CMS_CA_CRL_ISSUING_POINT_INIT_FAILED", + issuePointId, e.toString())); + } + } + + /* + if (mMasterCRLIssuePoint == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_NO_FULL_CRL", PROP_MASTER_CRL)); + throw new ECAException(CAResources.NO_CONFIG_FOR_MASTER_CRL); + } + */ + log(ILogger.LL_INFO, "CRL Issuing Points inited"); + } + + public String getOfficialName() { + return OFFICIAL_NAME; + } + + public long getNumOCSPRequest() { + return mNumOCSPRequest; + } + + public long getOCSPRequestTotalTime() { + return mTotalTime; + } + + public long getOCSPTotalData() { + return mTotalData; + } + + public long getOCSPTotalSignTime() { + return mSignTime; + } + + public long getOCSPTotalLookupTime() { + return mLookupTime; + } + + public ResponderID getResponderIDByName() { + try { + X500Name name = getOCSPX500Name(); + Name.Template nameTemplate = new Name.Template(); + + return new NameID((Name) nameTemplate.decode( + new ByteArrayInputStream(name.getEncoded()))); + } catch (IOException e) { + return null; + } catch (InvalidBERException e) { + return null; + } + } + + public ResponderID getResponderIDByHash() { + + /* + KeyHash ::= OCTET STRING --SHA-1 hash of responder's public key + --(excluding the tag and length fields) + */ + PublicKey publicKey = getOCSPSigningUnit().getPublicKey(); + MessageDigest md = null; + + try { + md = MessageDigest.getInstance("SHA1"); + } catch (NoSuchAlgorithmException e) { + return null; + } + md.update(publicKey.getEncoded()); + byte digested[] = md.digest(); + + return new KeyHashID(new OCTET_STRING(digested)); + } + + /** + * Process OCSPRequest. + */ + public OCSPResponse validate(OCSPRequest request) + throws EBaseException { + + if (!mEnableOCSP) { + CMS.debug("Local ocsp service is disable."); + return null; + } + + mNumOCSPRequest++; + IStatsSubsystem statsSub = (IStatsSubsystem) CMS.getSubsystem("stats"); + long startTime = CMS.getCurrentDate().getTime(); + try { + //log(ILogger.LL_INFO, "start OCSP request"); + TBSRequest tbsReq = request.getTBSRequest(); + + // (3) look into database to check the + // certificate's status + Vector singleResponses = new Vector(); + if (statsSub != null) { + statsSub.startTiming("lookup"); + } + + long lookupStartTime = CMS.getCurrentDate().getTime(); + for (int i = 0; i < tbsReq.getRequestCount(); i++) { + com.netscape.cmsutil.ocsp.Request req = + tbsReq.getRequestAt(i); + CertID cid = req.getCertID(); + SingleResponse sr = processRequest(cid); + + singleResponses.addElement(sr); + } + long lookupEndTime = CMS.getCurrentDate().getTime(); + if (statsSub != null) { + statsSub.endTiming("lookup"); + } + mLookupTime += lookupEndTime - lookupStartTime; + + if (statsSub != null) { + statsSub.startTiming("build_response"); + } + SingleResponse res[] = new SingleResponse[singleResponses.size()]; + + singleResponses.copyInto(res); + + ResponderID rid = null; + if (mByName) { + if (mResponderIDByName == null) { + mResponderIDByName = getResponderIDByName(); + } + rid = mResponderIDByName; + } else { + if (mResponderIDByHash == null) { + mResponderIDByHash = getResponderIDByHash(); + } + rid = mResponderIDByHash; + } + + Extension nonce[] = null; + + for (int j = 0; j < tbsReq.getExtensionsCount(); j++) { + Extension thisExt = tbsReq.getRequestExtensionAt(j); + + if (thisExt.getExtnId().equals(OCSP_NONCE)) { + nonce = new Extension[1]; + nonce[0] = thisExt; + } + } + ResponseData rd = new ResponseData(rid, + new GeneralizedTime(CMS.getCurrentDate()), res, nonce); + if (statsSub != null) { + statsSub.endTiming("build_response"); + } + + if (statsSub != null) { + statsSub.startTiming("signing"); + } + long signStartTime = CMS.getCurrentDate().getTime(); + BasicOCSPResponse basicRes = sign(rd); + long signEndTime = CMS.getCurrentDate().getTime(); + mSignTime += signEndTime - signStartTime; + if (statsSub != null) { + statsSub.endTiming("signing"); + } + + OCSPResponse response = new OCSPResponse( + OCSPResponseStatus.SUCCESSFUL, + new ResponseBytes(ResponseBytes.OCSP_BASIC, + new OCTET_STRING(ASN1Util.encode(basicRes)))); + + //log(ILogger.LL_INFO, "done OCSP request"); + long endTime = CMS.getCurrentDate().getTime(); + mTotalTime += endTime - startTime; + return response; + } catch (Exception e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_OCSP_REQUEST", e.toString())); + return null; + } + } + + private BasicOCSPResponse sign(ResponseData rd) throws EBaseException { + try { + DerOutputStream out = new DerOutputStream(); + DerOutputStream tmp = new DerOutputStream(); + + String algname = mOCSPSigningUnit.getDefaultAlgorithm(); + + byte rd_data[] = ASN1Util.encode(rd); + if (rd_data != null) { + mTotalData += rd_data.length; + } + rd.encode(tmp); + AlgorithmId.get(algname).encode(tmp); + CMS.debug("adding signature"); + byte[] signature = mOCSPSigningUnit.sign(rd_data, algname); + + tmp.putBitString(signature); + // optional, put the certificate chains in also + + DerOutputStream tmpChain = new DerOutputStream(); + DerOutputStream tmp1 = new DerOutputStream(); + java.security.cert.X509Certificate chains[] = + mOCSPCertChain.getChain(); + + for (int i = 0; i < chains.length; i++) { + tmpChain.putDerValue(new DerValue(chains[i].getEncoded())); + } + tmp1.write(DerValue.tag_Sequence, tmpChain); + tmp.write(DerValue.createTag(DerValue.TAG_CONTEXT, true, (byte) 0), + tmp1); + + out.write(DerValue.tag_Sequence, tmp); + + BasicOCSPResponse response = new BasicOCSPResponse(out.toByteArray()); + + return response; + } catch (Exception e) { + e.printStackTrace(); + // error e + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_CA_OCSP_SIGN", e.toString())); + return null; + } + } + + private SingleResponse processRequest(CertID cid) { + INTEGER serialNo = cid.getSerialNumber(); + + CMS.debug("process request " + serialNo); + CertStatus certStatus = null; + GeneralizedTime thisUpdate = new GeneralizedTime(CMS.getCurrentDate()); + GeneralizedTime nextUpdate = null; + + boolean ocspUseCache = true; + + try { + /* enable OCSP cache by default */ + ocspUseCache = mConfig.getBoolean("ocspUseCache", false); + } catch (EBaseException e) { + } + + if (ocspUseCache) { + String issuingPointId = PROP_MASTER_CRL; + + try { + issuingPointId = mConfig.getString( + "ocspUseCacheIssuingPointId", PROP_MASTER_CRL); + + } catch (EBaseException e) { + } + CRLIssuingPoint point = (CRLIssuingPoint) + getCRLIssuingPoint(issuingPointId); + + if (point.isCRLCacheEnabled()) { + // only do this if cache is enabled + BigInteger sno = new BigInteger(serialNo.toString()); + boolean checkDeltaCache = false; + boolean includeExpiredCerts = false; + + try { + checkDeltaCache = mConfig.getBoolean("ocspUseCacheCheckDeltaCache", false); + } catch (EBaseException e) { + } + try { + includeExpiredCerts = mConfig.getBoolean("ocspUseCacheIncludeExpiredCerts", false); + } catch (EBaseException e) { + } + Date revokedOn = point.getRevocationDateFromCache( + sno, checkDeltaCache, includeExpiredCerts); + + if (revokedOn == null) { + certStatus = new GoodInfo(); + } else { + certStatus = new RevokedInfo(new GeneralizedTime(revokedOn)); + } + return new SingleResponse(cid, certStatus, thisUpdate, nextUpdate); + } + } + + try { + ICertRecord rec = mCertRepot.readCertificateRecord(serialNo); + String status = rec.getStatus(); + + if (status == null) { + certStatus = new UnknownInfo(); + } else if (status.equals(CertRecord.STATUS_VALID)) { + certStatus = new GoodInfo(); + } else if (status.equals(CertRecord.STATUS_INVALID)) { + // not yet valid + certStatus = new UnknownInfo(); + } else if (status.equals(CertRecord.STATUS_REVOKED)) { + certStatus = new RevokedInfo(new GeneralizedTime(rec.getRevokedOn())); + } else if (status.equals(CertRecord.STATUS_EXPIRED)) { + certStatus = new UnknownInfo(); + } else if (status.equals(CertRecord.STATUS_REVOKED_EXPIRED)) { + certStatus = new RevokedInfo(new GeneralizedTime(rec.getRevokedOn())); + } else { + certStatus = new UnknownInfo(); + } + } catch (Exception e) { + // not found + certStatus = new UnknownInfo(); // not issued not all + } + + return new SingleResponse(cid, certStatus, thisUpdate, nextUpdate); + } +} diff --git a/base/ca/src/com/netscape/ca/SigningUnit.java b/base/ca/src/com/netscape/ca/SigningUnit.java new file mode 100644 index 000000000..85e3621d7 --- /dev/null +++ b/base/ca/src/com/netscape/ca/SigningUnit.java @@ -0,0 +1,389 @@ +// --- 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.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.SignatureException; + +import netscape.security.x509.AlgorithmId; +import netscape.security.x509.X509CertImpl; +import netscape.security.x509.X509Key; + +import org.mozilla.jss.CryptoManager; +import org.mozilla.jss.NoSuchTokenException; +import org.mozilla.jss.crypto.CryptoToken; +import org.mozilla.jss.crypto.ObjectNotFoundException; +import org.mozilla.jss.crypto.PrivateKey; +import org.mozilla.jss.crypto.Signature; +import org.mozilla.jss.crypto.SignatureAlgorithm; +import org.mozilla.jss.crypto.TokenException; +import org.mozilla.jss.crypto.X509Certificate; +import org.mozilla.jss.util.IncorrectPasswordException; +import org.mozilla.jss.util.PasswordCallback; + +import com.netscape.certsrv.apps.CMS; +import com.netscape.certsrv.base.EBaseException; +import com.netscape.certsrv.base.IConfigStore; +import com.netscape.certsrv.base.ISubsystem; +import com.netscape.certsrv.ca.ECAException; +import com.netscape.certsrv.common.Constants; +import com.netscape.certsrv.logging.ILogger; +import com.netscape.certsrv.security.ISigningUnit; +import com.netscape.cmscore.security.JssSubsystem; +import com.netscape.cmsutil.util.Cert; + +/** + * CA signing unit based on JSS. + * + * $Revision$ $Date$ + */ + +public final class SigningUnit implements ISigningUnit { + public static final String PROP_DEFAULT_SIGNALG = "defaultSigningAlgorithm"; + public static final String PROP_CERT_NICKNAME = "cacertnickname"; + // This signing unit is being used in OCSP and CRL also. So + // it is better to have a more generic name + public static final String PROP_RENAMED_CERT_NICKNAME = "certnickname"; + public static final String PROP_TOKEN_NAME = "tokenname"; + public static final String PROP_NEW_NICKNAME = "newNickname"; + + private CryptoManager mManager = null; + private CryptoToken mToken = null; + private PublicKey mPubk = null; + private PrivateKey mPrivk = null; + + protected X509Certificate mCert = null; + protected X509CertImpl mCertImpl = null; + protected String mNickname = null; + + private boolean mInited = false; + private ILogger mLogger = CMS.getLogger(); + private IConfigStore mConfig; + + private ISubsystem mOwner = null; + + private String mDefSigningAlgname = null; + private SignatureAlgorithm mDefSigningAlgorithm = null; + + public SigningUnit() { + } + + public X509Certificate getCert() { + return mCert; + } + + public X509CertImpl getCertImpl() { + return mCertImpl; + } + + public String getNickname() { + return mNickname; + } + + public String getNewNickName() throws EBaseException { + return mConfig.getString(PROP_NEW_NICKNAME, ""); + } + + public void setNewNickName(String name) { + mConfig.putString(PROP_NEW_NICKNAME, name); + } + + public PublicKey getPublicKey() { + return mPubk; + } + + public PrivateKey getPrivateKey() { + return mPrivk; + } + + public void updateConfig(String nickname, String tokenname) { + mConfig.putString(PROP_CERT_NICKNAME, nickname); + mConfig.putString(PROP_TOKEN_NAME, tokenname); + } + + public String getTokenName() throws EBaseException { + return mConfig.getString(PROP_TOKEN_NAME); + } + + public String getNickName() throws EBaseException { + try { + return mConfig.getString(PROP_RENAMED_CERT_NICKNAME); + } catch (EBaseException e) { + return mConfig.getString(PROP_CERT_NICKNAME); + } + } + + public void init(ISubsystem owner, IConfigStore config) + throws EBaseException { + mOwner = owner; + mConfig = config; + + String tokenname = null; + try { + mManager = CryptoManager.getInstance(); + + mNickname = getNickName(); + + tokenname = config.getString(PROP_TOKEN_NAME); + if (tokenname.equalsIgnoreCase(Constants.PR_INTERNAL_TOKEN) || + tokenname.equalsIgnoreCase("Internal Key Storage Token")) { + mToken = mManager.getInternalKeyStorageToken(); + setNewNickName(mNickname); + } else { + mToken = mManager.getTokenByName(tokenname); + mNickname = tokenname + ":" + mNickname; + setNewNickName(mNickname); + } + CMS.debug(config.getName() + " Signing Unit nickname " + mNickname); + CMS.debug("Got token " + tokenname + " by name"); + + PasswordCallback cb = JssSubsystem.getInstance().getPWCB(); + + mToken.login(cb); // ONE_TIME by default. + + mCert = mManager.findCertByNickname(mNickname); + CMS.debug("Found cert by nickname: '" + mNickname + "' with serial number: " + mCert.getSerialNumber()); + + mCertImpl = new X509CertImpl(mCert.getEncoded()); + CMS.debug("converted to x509CertImpl"); + + mPrivk = mManager.findPrivKeyByCert(mCert); + CMS.debug("Got private key from cert"); + + mPubk = mCert.getPublicKey(); + CMS.debug("Got public key from cert"); + + // get def alg and check if def sign alg is valid for token. + mDefSigningAlgname = config.getString(PROP_DEFAULT_SIGNALG); + mDefSigningAlgorithm = + checkSigningAlgorithmFromName(mDefSigningAlgname); + CMS.debug( + "got signing algorithm " + mDefSigningAlgorithm); + mInited = true; + } catch (java.security.cert.CertificateException e) { + CMS.debug("SigningUnit init: debug " + e.toString()); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_CA_CERT", e.getMessage())); + throw new ECAException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", e.toString())); + } catch (CryptoManager.NotInitializedException e) { + CMS.debug("SigningUnit init: debug " + e.toString()); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_TOKEN_INIT", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_CRYPTO_NOT_INITIALIZED")); + } catch (IncorrectPasswordException e) { + CMS.debug("SigningUnit init: debug " + e.toString()); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_WRONG_PWD", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_INVALID_PASSWORD")); + } catch (NoSuchTokenException e) { + CMS.debug("SigningUnit init: debug " + e.toString()); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_TOKEN_NOT_FOUND", tokenname, e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_TOKEN_NOT_FOUND", tokenname)); + } catch (ObjectNotFoundException e) { + CMS.debug("SigningUnit init: debug " + e.toString()); + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_CERT_NOT_FOUND", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_CERT_OBJECT_NOT_FOUND")); + } catch (TokenException e) { + CMS.debug("SigningUnit init: debug " + e.toString()); + log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + throw new ECAException(CMS.getUserMessage("CMS_CA_TOKEN_ERROR")); + } catch (Exception e) { + CMS.debug("SigningUnit init: debug " + e.toString()); + } + } + + /** + * Check if the signing algorithm name is supported and valid for this + * signing unit's token and key. + * + * @param algname a signing algorithm name from JCA. + * @return the mapped JSS signature algorithm object. + * + * @exception EBaseException if signing algorithm is not supported. + */ + public SignatureAlgorithm checkSigningAlgorithmFromName(String algname) + throws EBaseException { + try { + SignatureAlgorithm sigalg = null; + + sigalg = mapAlgorithmToJss(algname); + if (sigalg == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_ALG_NOT_SUPPORTED", algname, "")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED", algname)); + } + Signature signer = mToken.getSignatureContext(sigalg); + + signer.initSign(mPrivk); + return sigalg; + } catch (NoSuchAlgorithmException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_ALG_NOT_SUPPORTED", algname, e.toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED", algname)); + } catch (TokenException e) { + // from get signature context or from initSign + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_ALG_NOT_SUPPORTED", algname, e.toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED", algname)); + } catch (InvalidKeyException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_ALG_NOT_SUPPORTED", algname, e.toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED_FOR_KEY", algname)); + } + } + + /** + * @param algname is expected to be one of JCA's algorithm names. + */ + public byte[] sign(byte[] data, String algname) + throws EBaseException { + if (!mInited) { + throw new EBaseException("CASigningUnit not initialized!"); + } + try { + // XXX for now do this mapping until James changes the names + // to match JCA names and provide a getAlgorithm method. + SignatureAlgorithm signAlg = mDefSigningAlgorithm; + + if (algname != null) { + signAlg = checkSigningAlgorithmFromName(algname); + } + + // XXX use a pool of signers based on alg ? + // XXX Map algor. name to id. hack: use hardcoded define for now. + CMS.debug( + "Getting algorithm context for " + algname + " " + signAlg); + Signature signer = mToken.getSignatureContext(signAlg); + + signer.initSign(mPrivk); + signer.update(data); + // XXX add something more descriptive. + CMS.debug("Signing Certificate"); + return signer.sign(); + } catch (NoSuchAlgorithmException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED", algname)); + } catch (TokenException e) { + // from get signature context or from initSign + log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + // XXX fix this exception later. + throw new EBaseException(e.toString()); + } catch (InvalidKeyException e) { + // XXX fix this exception later. + throw new EBaseException(e.toString()); + } catch (SignatureException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + // XXX fix this exception later. + throw new EBaseException(e.toString()); + } + } + + public boolean verify(byte[] data, byte[] signature, String algname) + throws EBaseException { + if (!mInited) { + throw new EBaseException("CASigningUnit not initialized!"); + } + try { + SignatureAlgorithm signAlg = mapAlgorithmToJss(algname); + + if (signAlg == null) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("CMSCORE_CA_SIGNING_ALG_NOT_SUPPORTED", algname, "")); + throw new ECAException( + CMS.getUserMessage("CMS_CA_SIGNING_ALGOR_NOT_SUPPORTED", algname)); + } + // XXX make this configurable. hack: use hardcoded for now. + Signature signer = mToken.getSignatureContext(signAlg); + + signer.initVerify(mPubk); + signer.update(data); + return signer.verify(signature); + } catch (NoSuchAlgorithmException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + // XXX fix this exception later. + throw new EBaseException(e.toString()); + } catch (TokenException e) { + // from get signature context or from initSign + log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + // XXX fix this exception later. + throw new EBaseException(e.toString()); + } catch (InvalidKeyException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + // XXX fix this exception later. + throw new EBaseException(e.toString()); + } catch (SignatureException e) { + log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", e.toString())); + // XXX fix this exception later. + throw new EBaseException(e.toString()); + } + } + + private void log(int level, String msg) { + if (mLogger == null) + return; + mLogger.log(ILogger.EV_SYSTEM, null, ILogger.S_CA, + level, "CASigningUnit: " + msg); + } + + /** + * returns default signature algorithm + */ + public SignatureAlgorithm getDefaultSignatureAlgorithm() { + return mDefSigningAlgorithm; + } + + /** + * returns default signing algorithm name. + */ + public String getDefaultAlgorithm() { + return mDefSigningAlgname; + } + + public void setDefaultAlgorithm(String algorithm) throws EBaseException { + mConfig.putString(PROP_DEFAULT_SIGNALG, algorithm); + mDefSigningAlgname = algorithm; + log(ILogger.LL_INFO, + "Default signing algorithm is set to " + algorithm); + } + + /** + * get all possible algorithms for the CA signing key type. + */ + public String[] getAllAlgorithms() throws EBaseException { + byte[] keybytes = mPubk.getEncoded(); + X509Key key = new X509Key(); + + try { + key.decode(keybytes); + } catch (java.security.InvalidKeyException e) { + String msg = "Invalid encoding in CA signing key."; + + log(ILogger.LL_FAILURE, CMS.getLogMessage("OPERATION_ERROR", msg)); + throw new EBaseException(CMS.getUserMessage("CMS_BASE_INTERNAL_ERROR", msg)); + } + + if (key.getAlgorithmId().getOID().equals(AlgorithmId.DSA_oid)) { + return AlgorithmId.DSA_SIGNING_ALGORITHMS; + } else { + return AlgorithmId.ALL_SIGNING_ALGORITHMS; + } + } + + public static SignatureAlgorithm mapAlgorithmToJss(String algname) { + return Cert.mapAlgorithmToJss(algname); + } +} -- cgit