// --- 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.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
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.base.PKIException;
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;
/**
* 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 Map getNonces(HttpServletRequest request, String name) {
// Create a new session or use an existing one.
HttpSession session = request.getSession(true);
if (session == null) {
throw new PKIException("Unable to create session.");
}
// Lock the session to prevent concurrent access.
// http://yet-another-dev.blogspot.com/2009/08/synchronizing-httpsession.html
Object lock = request.getSession().getId().intern();
synchronized (lock) {
// Find the existing storage in the session.
@SuppressWarnings("unchecked")
Map nonces = (Map)session.getAttribute("nonces-"+name);
if (nonces == null) {
// If not present, create a new storage.
nonces = Collections.synchronizedMap(new Nonces(mMaxNonces));
// Put the storage in the session.
session.setAttribute("nonces-"+name, nonces);
}
return nonces;
}
}
/**
* 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);
// 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();
}
mCRLIssuePoints.clear();
if (mMasterCRLIssuePoint != null) {
mMasterCRLIssuePoint.shutdown();
}
if (mCertRepot != null) {
mCertRepot.shutdown();
}
if (mPublisherProcessor != 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 = 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 = null;
try {
in = new FileInputStream(path);
in.read(b);
} finally {
if (in != null)
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 = 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 = 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();
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.
CRLIssuingPoint masterCRLIssuePoint = null;
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 (masterCRLIssuePoint == null &&
issuePointId.equals(PROP_MASTER_CRL))
masterCRLIssuePoint = 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()));
}
}
mMasterCRLIssuePoint = masterCRLIssuePoint;
/*
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()));
throw new EBaseException(e.toString());
}
}
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()));
throw new EBaseException(e.toString());
}
}
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);
}
}