Java tutorial
// --- 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.cmscore.apps; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.math.BigInteger; import java.security.NoSuchAlgorithmException; import java.security.Security; import java.security.SignatureException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.ResourceBundle; import java.util.Timer; import java.util.Vector; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import org.apache.commons.lang.StringUtils; import org.apache.xerces.parsers.DOMParser; import org.dogtagpki.legacy.core.policy.GeneralNameUtil; import org.dogtagpki.legacy.policy.IGeneralNameAsConstraintsConfig; import org.dogtagpki.legacy.policy.IGeneralNamesAsConstraintsConfig; import org.dogtagpki.legacy.policy.IGeneralNamesConfig; import org.dogtagpki.legacy.policy.ISubjAltNameConfig; import org.mozilla.jss.CertificateUsage; import org.mozilla.jss.CryptoManager; 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.util.PasswordCallback; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import com.netscape.certsrv.apps.CMS; import com.netscape.certsrv.apps.ICMSEngine; import com.netscape.certsrv.apps.ICommandQueue; import com.netscape.certsrv.authentication.ISharedToken; import com.netscape.certsrv.authority.IAuthority; import com.netscape.certsrv.base.EBaseException; import com.netscape.certsrv.base.IArgBlock; import com.netscape.certsrv.base.ICRLPrettyPrint; import com.netscape.certsrv.base.ICertPrettyPrint; import com.netscape.certsrv.base.IConfigStore; import com.netscape.certsrv.base.IExtPrettyPrint; import com.netscape.certsrv.base.IPrettyPrintFormat; import com.netscape.certsrv.base.ISecurityDomainSessionTable; import com.netscape.certsrv.base.ISubsystem; import com.netscape.certsrv.base.ITimeSource; import com.netscape.certsrv.base.SessionContext; import com.netscape.certsrv.ca.ICRLIssuingPoint; import com.netscape.certsrv.ca.ICertificateAuthority; import com.netscape.certsrv.common.Constants; import com.netscape.certsrv.common.ICMSRequest; import com.netscape.certsrv.common.NameValuePairs; import com.netscape.certsrv.connector.IHttpConnection; import com.netscape.certsrv.connector.IPKIMessage; import com.netscape.certsrv.connector.IRemoteAuthority; import com.netscape.certsrv.connector.IRequestEncoder; import com.netscape.certsrv.connector.IResender; import com.netscape.certsrv.dbs.certdb.ICertificateRepository; import com.netscape.certsrv.dbs.crldb.ICRLIssuingPointRecord; import com.netscape.certsrv.dbs.repository.IRepositoryRecord; import com.netscape.certsrv.kra.IKeyRecoveryAuthority; import com.netscape.certsrv.ldap.ELdapException; import com.netscape.certsrv.ldap.ILdapAuthInfo; import com.netscape.certsrv.ldap.ILdapConnFactory; import com.netscape.certsrv.ldap.ILdapConnInfo; import com.netscape.certsrv.logging.ConsoleError; import com.netscape.certsrv.logging.ELogException; import com.netscape.certsrv.logging.IAuditor; import com.netscape.certsrv.logging.ILogEvent; import com.netscape.certsrv.logging.ILogEventListener; import com.netscape.certsrv.logging.ILogQueue; import com.netscape.certsrv.logging.ILogger; import com.netscape.certsrv.logging.SystemEvent; import com.netscape.certsrv.notification.IEmailFormProcessor; import com.netscape.certsrv.notification.IEmailResolver; import com.netscape.certsrv.notification.IEmailResolverKeys; import com.netscape.certsrv.notification.IEmailTemplate; import com.netscape.certsrv.notification.IMailNotification; import com.netscape.certsrv.password.IPasswordCheck; import com.netscape.certsrv.profile.IEnrollProfile; import com.netscape.certsrv.ra.IRegistrationAuthority; import com.netscape.certsrv.request.IRequest; import com.netscape.certsrv.request.IRequestQueue; import com.netscape.certsrv.request.RequestStatus; import com.netscape.cms.logging.Logger; import com.netscape.cmscore.authentication.AuthSubsystem; import com.netscape.cmscore.authentication.VerifiedCert; import com.netscape.cmscore.authentication.VerifiedCerts; import com.netscape.cmscore.authorization.AuthzSubsystem; import com.netscape.cmscore.base.ArgBlock; import com.netscape.cmscore.base.FileConfigStore; import com.netscape.cmscore.base.SubsystemRegistry; import com.netscape.cmscore.cert.CertPrettyPrint; import com.netscape.cmscore.cert.CertUtils; import com.netscape.cmscore.cert.CrlCachePrettyPrint; import com.netscape.cmscore.cert.CrlPrettyPrint; import com.netscape.cmscore.cert.ExtPrettyPrint; import com.netscape.cmscore.cert.OidLoaderSubsystem; import com.netscape.cmscore.cert.X500NameSubsystem; import com.netscape.cmscore.connector.HttpConnection; import com.netscape.cmscore.connector.HttpPKIMessage; import com.netscape.cmscore.connector.HttpRequestEncoder; import com.netscape.cmscore.connector.Resender; import com.netscape.cmscore.dbs.CRLIssuingPointRecord; import com.netscape.cmscore.dbs.CertificateRepository; import com.netscape.cmscore.dbs.DBSubsystem; import com.netscape.cmscore.dbs.RepositoryRecord; import com.netscape.cmscore.jobs.JobsScheduler; import com.netscape.cmscore.ldapconn.LdapAnonConnFactory; import com.netscape.cmscore.ldapconn.LdapAuthInfo; import com.netscape.cmscore.ldapconn.LdapBoundConnFactory; import com.netscape.cmscore.ldapconn.LdapBoundConnection; import com.netscape.cmscore.ldapconn.LdapConnInfo; import com.netscape.cmscore.ldapconn.PKISocketFactory; import com.netscape.cmscore.logging.Auditor; import com.netscape.cmscore.logging.LogSubsystem; import com.netscape.cmscore.notification.EmailFormProcessor; import com.netscape.cmscore.notification.EmailResolverKeys; import com.netscape.cmscore.notification.EmailTemplate; import com.netscape.cmscore.notification.ReqCertSANameEmailResolver; import com.netscape.cmscore.registry.PluginRegistry; import com.netscape.cmscore.request.CertRequestConstants; import com.netscape.cmscore.request.RequestSubsystem; import com.netscape.cmscore.security.JssSubsystem; import com.netscape.cmscore.security.PWCBsdr; import com.netscape.cmscore.security.PWsdrCache; import com.netscape.cmscore.session.LDAPSecurityDomainSessionTable; import com.netscape.cmscore.session.SecurityDomainSessionTable; import com.netscape.cmscore.session.SessionTimer; import com.netscape.cmscore.time.SimpleTimeSource; import com.netscape.cmscore.usrgrp.UGSubsystem; import com.netscape.cmscore.util.Debug; import com.netscape.cmsutil.crypto.CryptoUtil; import com.netscape.cmsutil.net.ISocketFactory; import com.netscape.cmsutil.password.IPasswordStore; import com.netscape.cmsutil.password.NuxwdogPasswordStore; import com.netscape.cmsutil.util.Cert; import com.netscape.cmsutil.util.Utils; import netscape.ldap.LDAPConnection; import netscape.ldap.LDAPException; import netscape.ldap.LDAPSSLSocketFactoryExt; import netscape.ldap.LDAPSocketFactory; import netscape.security.extensions.CertInfo; import netscape.security.pkcs.ContentInfo; import netscape.security.pkcs.PKCS7; import netscape.security.pkcs.SignerInfo; import netscape.security.util.ObjectIdentifier; import netscape.security.x509.AlgorithmId; import netscape.security.x509.CertificateChain; import netscape.security.x509.Extension; import netscape.security.x509.GeneralName; import netscape.security.x509.X509CRLImpl; import netscape.security.x509.X509CertImpl; import netscape.security.x509.X509CertInfo; public class CMSEngine implements ICMSEngine { public static org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(CMSEngine.class); private static final String ID = "MAIN"; private static final String PROP_SUBSYSTEM = "subsystem"; private static final String PROP_ID = "id"; private static final String PROP_CLASS = "class"; private static final String PROP_ENABLED = "enabled"; private static final String SERVER_XML = "server.xml"; // used for testing HSM issues public static final String PROP_SIGNED_AUDIT_CERT_NICKNAME = "log.instance.SignedAudit.signedAuditCertNickname"; public static final SubsystemRegistry mSSReg = SubsystemRegistry.getInstance(); public String instanceDir; /* path to instance <server-root>/cert-<instance-name> */ private String instanceId; private int pid; private CryptoManager mManager = null; private IConfigStore mConfig = null; private boolean mExcludedLdapAttrsEnabled = false; // AutoSD : AutoShutdown private String mAutoSD_CrumbFile = null; private boolean mAutoSD_Restart = false; private int mAutoSD_RestartMax = 3; private int mAutoSD_RestartCount = 0; private String mSAuditCertNickName = null; private PrivateKey mSigningKey = null; private byte[] mSigningData = null; @SuppressWarnings("unused") private ISubsystem mOwner; private long mStartupTime = 0; private boolean isStarted = false; private StringBuffer mWarning = new StringBuffer(); private ITimeSource mTimeSource = null; private IPasswordStore mPasswordStore = null; private WarningListener mWarningListener = null; private ILogQueue mQueue = null; private ISecurityDomainSessionTable mSecurityDomainSessionTable = null; private String mConfigSDSessionId = null; private Timer mSDTimer = null; private String mServerCertNickname = null; private String serverStatus = null; // static subsystems - must be singletons public Map<String, SubsystemInfo> staticSubsystems = new LinkedHashMap<>(); // dynamic subsystems are loaded at init time, not necessarily singletons. public Map<String, SubsystemInfo> dynSubsystems = new LinkedHashMap<>(); // final static subsystems - must be singletons. public Map<String, SubsystemInfo> finalSubsystems = new LinkedHashMap<>(); private static final int IP = 0; private static final int PORT = 1; @SuppressWarnings("unused") private static final int HOST = 2; private static final int AGENT = 0; private static final int ADMIN = 1; private static final int EE_SSL = 2; private static final int EE_NON_SSL = 3; private static final int EE_CLIENT_AUTH_SSL = 4; private static String info[][] = { { null, null, null }, //agent { null, null, null }, //admin { null, null, null }, //sslEE { null, null, null }, //non_sslEE { null, null, null } //ssl_clientauth_EE }; private static final int PW_OK = 0; private static final int PW_BAD_SETUP = 1; private static final int PW_INVALID_PASSWORD = 2; private static final int PW_CANNOT_CONNECT = 3; private static final int PW_NO_USER = 4; private static final int PW_MAX_ATTEMPTS = 3; /** * private constructor. */ public CMSEngine() { } /** * gets this ID */ public String getId() { return ID; } /** * should never be called. returns error. */ public void setId(String id) throws EBaseException { throw new EBaseException(CMS.getUserMessage("CMS_BASE_INVALID_OPERATION")); } /** * Retrieves the instance root path of this server. */ public String getInstanceDir() { return instanceDir; } public boolean startedByNuxwdog() { String wdPipeName = System.getenv("WD_PIPE_NAME"); if (StringUtils.isNotEmpty(wdPipeName)) { return true; } return false; } public synchronized IPasswordStore getPasswordStore() throws EBaseException { if (mPasswordStore == null) { String pwdClass = null; String pwdPath = null; if (startedByNuxwdog()) { pwdClass = NuxwdogPasswordStore.class.getName(); // note: pwdPath is expected to be null in this case } else { pwdClass = mConfig.getString("passwordClass"); pwdPath = mConfig.getString("passwordFile", null); } try { mPasswordStore = (IPasswordStore) Class.forName(pwdClass).newInstance(); mPasswordStore.init(pwdPath); mPasswordStore.setId(instanceId); } catch (Exception e) { logger.error("Cannot get password store: " + e); throw new EBaseException(e); } } return mPasswordStore; } public void initializePasswordStore(IConfigStore config) throws EBaseException, IOException { logger.debug("CMSEngine.initializePasswordStore() begins"); // create and initialize mPasswordStore getPasswordStore(); boolean skipPublishingCheck = config.getBoolean("cms.password.ignore.publishing.failure", true); String pwList = config.getString("cms.passwordlist", "internaldb,replicationdb"); String tags[] = StringUtils.split(pwList, ","); for (String tag : tags) { int iteration = 0; int result = PW_INVALID_PASSWORD; String binddn; String authType; LdapConnInfo connInfo = null; logger.debug("CMSEngine.initializePasswordStore(): tag=" + tag); if (tag.equals("internaldb")) { authType = config.getString("internaldb.ldapauth.authtype", "BasicAuth"); if (!authType.equals("BasicAuth")) continue; connInfo = new LdapConnInfo(config.getString("internaldb.ldapconn.host"), config.getInteger("internaldb.ldapconn.port"), config.getBoolean("internaldb.ldapconn.secureConn")); binddn = config.getString("internaldb.ldapauth.bindDN"); } else if (tag.equals("replicationdb")) { authType = config.getString("internaldb.ldapauth.authtype", "BasicAuth"); if (!authType.equals("BasicAuth")) continue; connInfo = new LdapConnInfo(config.getString("internaldb.ldapconn.host"), config.getInteger("internaldb.ldapconn.port"), config.getBoolean("internaldb.ldapconn.secureConn")); binddn = "cn=Replication Manager masterAgreement1-" + config.getString("machineName", "") + "-" + config.getString("instanceId", "") + ",cn=config"; } else if (tags.equals("CA LDAP Publishing")) { authType = config.getString("ca.publish.ldappublish.ldap.ldapauth.authtype", "BasicAuth"); if (!authType.equals("BasicAuth")) continue; connInfo = new LdapConnInfo(config.getString("ca.publish.ldappublish.ldap.ldapconn.host"), config.getInteger("ca.publish.ldappublish.ldap.ldapconn.port"), config.getBoolean("ca.publish.ldappublish.ldap.ldapconn.secureConn")); binddn = config.getString("ca.publish.ldappublish.ldap.ldapauth.bindDN"); } else { /* * This section assumes a generic format of * <authPrefix>.ldap.xxx * where <authPrefix> is specified under the tag substore * * e.g. if tag = "externalLDAP" * cms.passwordlist=...,externalLDAP * externalLDAP.authPrefix=auths.instance.UserDirEnrollment * * auths.instance.UserDirEnrollment.ldap.ldapauth.authtype=BasicAuth * auths.instance.UserDirEnrollment.ldap.ldapauth.bindDN=cn=Corporate Directory Manager * auths.instance.UserDirEnrollment.ldap.ldapauth.bindPWPrompt=externalLDAP * auths.instance.UserDirEnrollment.ldap.ldapconn.host=host.example.com * auths.instance.UserDirEnrollment.ldap.ldapconn.port=389 * auths.instance.UserDirEnrollment.ldap.ldapconn.secureConn=false */ String authPrefix = config.getString(tag + ".authPrefix", null); if (authPrefix == null) { logger.debug("CMSEngine.initializePasswordStore(): authPrefix not found...skipping"); continue; } logger.debug("CMSEngine.initializePasswordStore(): authPrefix=" + authPrefix); authType = config.getString(authPrefix + ".ldap.ldapauth.authtype", "BasicAuth"); logger.debug("CMSEngine.initializePasswordStore(): authType " + authType); if (!authType.equals("BasicAuth")) continue; connInfo = new LdapConnInfo(config.getString(authPrefix + ".ldap.ldapconn.host"), config.getInteger(authPrefix + ".ldap.ldapconn.port"), config.getBoolean(authPrefix + ".ldap.ldapconn.secureConn")); binddn = config.getString(authPrefix + ".ldap.ldapauth.bindDN", null); if (binddn == null) { logger.debug("CMSEngine.initializePasswordStore(): binddn not found...skipping"); continue; } } do { String passwd = mPasswordStore.getPassword(tag, iteration); result = testLDAPConnection(tag, connInfo, binddn, passwd); iteration++; } while ((result == PW_INVALID_PASSWORD) && (iteration < PW_MAX_ATTEMPTS)); if (result != PW_OK) { if ((result == PW_NO_USER) && (tag.equals("replicationdb"))) { logger.warn("CMSEngine: init(): password test execution failed for replicationdb" + "with NO_SUCH_USER. This may not be a latest instance. Ignoring .."); } else if (skipPublishingCheck && (result == PW_CANNOT_CONNECT) && (tag.equals("CA LDAP Publishing"))) { logger.warn("Unable to connect to the publishing database to check password, " + "but continuing to start up. Please check if publishing is operational."); } else { // password test failed logger.error("CMSEngine: init(): password test execution failed: " + result); throw new EBaseException("Password test execution failed. Is the database up?"); } } } } public int testLDAPConnection(String name, LdapConnInfo info, String binddn, String pwd) { int ret = PW_OK; if (StringUtils.isEmpty(pwd)) return PW_INVALID_PASSWORD; String host = info.getHost(); int port = info.getPort(); LDAPConnection conn = new LDAPConnection(getLDAPSocketFactory(info.getSecure())); logger.debug("testLDAPConnection connecting to " + host + ":" + port); try { conn.connect(host, port, binddn, pwd); } catch (LDAPException e) { switch (e.getLDAPResultCode()) { case LDAPException.NO_SUCH_OBJECT: logger.error("testLDAPConnection: The specified user " + binddn + " does not exist"); ret = PW_NO_USER; break; case LDAPException.INVALID_CREDENTIALS: logger.error("testLDAPConnection: Invalid Password"); ret = PW_INVALID_PASSWORD; break; default: logger.error("testLDAPConnection: Unable to connect to " + name + ": " + e); ret = PW_CANNOT_CONNECT; break; } } finally { try { if (conn != null) conn.disconnect(); } catch (Exception e) { } } return ret; } /** * initialize all static, dynamic and final static subsystems. * * @param owner null * @param config main config store. * @exception EBaseException if any error occur in subsystems during * initialization. */ public void init(ISubsystem owner, IConfigStore config) throws EBaseException { mOwner = owner; mConfig = config; int state = mConfig.getInteger("cs.state"); serverStatus = "starting"; instanceDir = config.getString("instanceRoot"); instanceId = config.getString("instanceId"); if (state == 1) { // configuration is complete, initialize password store try { initializePasswordStore(config); } catch (IOException e) { logger.error("Unable to initialize password store: " + e.getMessage(), e); throw new EBaseException("Exception while initializing password store: " + e); } } // my default is 1 day String flush_timeout = config.getString("securitydomain.flushinterval", "86400000"); String secdomain_source = config.getString("securitydomain.source", "memory"); String secdomain_check_interval = config.getString("securitydomain.checkinterval", "5000"); String tsClass = config.getString("timeSourceClass", null); if (tsClass != null) { try { mTimeSource = (ITimeSource) Class.forName(tsClass).newInstance(); } catch (Exception e) { // nothing to do } } if (mTimeSource == null) { // if time source is not set, set it to simple time source mTimeSource = new SimpleTimeSource(); } Security.addProvider(new netscape.security.provider.CMS()); loadSubsystems(); initSubsystems(); logger.debug("Java version: " + System.getProperty("java.version")); java.security.Provider ps[] = java.security.Security.getProviders(); if (ps == null || ps.length <= 0) { logger.debug("CMSEngine: Java Security Provider NONE"); } else { for (int x = 0; x < ps.length; x++) { logger.debug("CMSEngine: Java Security Provider " + x + " class=" + ps[x]); } } parseServerXML(); fixProxyPorts(); String sd = mConfig.getString("securitydomain.select", ""); if ((state == 1) && (!sd.equals("existing"))) { // check session domain table only if this is a // configured security domain host if (secdomain_source.equals("ldap")) { mSecurityDomainSessionTable = new LDAPSecurityDomainSessionTable( (new Long(flush_timeout)).longValue()); } else { mSecurityDomainSessionTable = new SecurityDomainSessionTable((new Long(flush_timeout)).longValue()); } mSDTimer = new Timer(); SessionTimer timertask = new SessionTimer(mSecurityDomainSessionTable); mSDTimer.schedule(timertask, 5, (new Long(secdomain_check_interval)).longValue()); } serverStatus = "running"; } /** * Parse server.xml to get the ports and IPs * @throws EBaseException */ private void parseServerXML() throws EBaseException { try { String instanceRoot = mConfig.getString("instanceRoot"); String path = instanceRoot + File.separator + "conf" + File.separator + SERVER_XML; DOMParser parser = new DOMParser(); parser.parse(path); NodeList nodes = parser.getDocument().getElementsByTagName("Connector"); String parentName = ""; String name = ""; String port = ""; for (int i = 0; i < nodes.getLength(); i++) { Element n = (Element) nodes.item(i); parentName = ""; Element p = (Element) n.getParentNode(); if (p != null) { parentName = p.getAttribute("name"); } name = n.getAttribute("name"); port = n.getAttribute("port"); // The "server.xml" file is parsed from top-to-bottom, and // supports BOTH "Port Separation" (the new default method) // as well as "Shared Ports" (the old legacy method). Since // both methods must be supported, the file structure MUST // conform to ONE AND ONLY ONE of the following formats: // // Port Separation: // // <Catalina> // ... // <!-- Port Separation: Unsecure Port --> // <Connector name="Unsecure" . . . // ... // <!-- Port Separation: Agent Secure Port --> // <Connector name="Agent" . . . // ... // <!-- Port Separation: Admin Secure Port --> // <Connector name="Admin" . . . // ... // <!-- Port Separation: EE Secure Port --> // <Connector name="EE" . . . // ... // </Catalina> // // // Shared Ports: // // <Catalina> // ... // <!-- Shared Ports: Unsecure Port --> // <Connector name="Unsecure" . . . // ... // <!-- Shared Ports: Agent, EE, and Admin Secure Port --> // <Connector name="Secure" . . . // ... // <!-- // <Connector name="Unused" . . . // --> // ... // <!-- // <Connector name="Unused" . . . // --> // ... // </Catalina> // if (parentName.equals("Catalina")) { if (name.equals("Unsecure")) { // Port Separation: Unsecure Port // OR // Shared Ports: Unsecure Port info[EE_NON_SSL][PORT] = port; } else if (name.equals("Agent")) { // Port Separation: Agent Secure Port info[AGENT][PORT] = port; } else if (name.equals("Admin")) { // Port Separation: Admin Secure Port info[ADMIN][PORT] = port; } else if (name.equals("EE")) { // Port Separation: EE Secure Port info[EE_SSL][PORT] = port; } else if (name.equals("EEClientAuth")) { // Port Separation: EE Client Auth Secure Port info[EE_CLIENT_AUTH_SSL][PORT] = port; } else if (name.equals("Secure")) { // Shared Ports: Agent, EE, and Admin Secure Port info[AGENT][PORT] = port; info[ADMIN][PORT] = port; info[EE_SSL][PORT] = port; info[EE_CLIENT_AUTH_SSL][PORT] = port; } } } } catch (Exception e) { logger.error("CMSEngine: parseServerXML exception: " + e.getMessage(), e); throw new EBaseException("CMSEngine: Cannot parse the configuration file. " + e.getMessage(), e); } } private void fixProxyPorts() throws EBaseException { try { String port = mConfig.getString("proxy.securePort", ""); if (!port.equals("")) { info[EE_SSL][PORT] = port; info[ADMIN][PORT] = port; info[AGENT][PORT] = port; info[EE_CLIENT_AUTH_SSL][PORT] = port; } port = mConfig.getString("proxy.unsecurePort", ""); if (!port.equals("")) { info[EE_NON_SSL][PORT] = port; } } catch (EBaseException e) { logger.error("CMSEngine: fixProxyPorts exception: " + e.getMessage(), e); throw e; } } public IConfigStore createFileConfigStore(String path) throws EBaseException { try { /* if the file is not there, create one */ File f = new File(path); f.createNewFile(); } catch (IOException e) { logger.error("Cannot create file: " + path + ": " + e.getMessage(), e); throw new EBaseException("Cannot create file: " + path + ": " + e.getMessage(), e); } return new FileConfigStore(path); } public IArgBlock createArgBlock() { return new ArgBlock(); } public IArgBlock createArgBlock(Hashtable<String, String> httpReq) { return new ArgBlock(httpReq); } public IArgBlock createArgBlock(String realm, Hashtable<String, String> httpReq) { return new ArgBlock(realm, httpReq); } public boolean isPreOpMode() { if (getCSState() == CMS.PRE_OP_MODE) return true; return false; } public boolean isRunningMode() { if (getCSState() == CMS.RUNNING_MODE) return true; return false; } public void setCSState(int mode) { mConfig.putInteger("cs.state", mode); } public int getCSState() { int mode = 0; try { mode = mConfig.getInteger("cs.state"); } catch (Exception e) { } return mode; } public IRepositoryRecord createRepositoryRecord() { return new RepositoryRecord(); } public ICRLIssuingPointRecord createCRLIssuingPointRecord(String id, BigInteger crlNumber, Long crlSize, Date thisUpdate, Date nextUpdate) { return new CRLIssuingPointRecord(id, crlNumber, crlSize, thisUpdate, nextUpdate); } public ISecurityDomainSessionTable getSecurityDomainSessionTable() { return mSecurityDomainSessionTable; } public String getCRLIssuingPointRecordName() { return CRLIssuingPointRecord.class.getName(); } public String getEEHost() { String host = ""; try { host = mConfig.getString("machineName"); } catch (Exception e) { } return host; } public String getEENonSSLHost() { String host = ""; try { host = mConfig.getString("machineName"); } catch (Exception e) { } return host; } public String getEENonSSLIP() { return info[EE_NON_SSL][IP]; } public String getEENonSSLPort() { return info[EE_NON_SSL][PORT]; } public String getEESSLHost() { String host = ""; try { host = mConfig.getString("machineName"); } catch (Exception e) { } return host; } public String getEESSLIP() { return info[EE_SSL][IP]; } public String getEESSLPort() { return info[EE_SSL][PORT]; } public String getEEClientAuthSSLPort() { return info[EE_CLIENT_AUTH_SSL][PORT]; } public String getAgentHost() { String host = ""; try { host = mConfig.getString("machineName"); } catch (Exception e) { } return host; } public String getAgentIP() { return info[AGENT][IP]; } public String getAgentPort() { return info[AGENT][PORT]; } public String getAdminHost() { String host = ""; try { host = mConfig.getString("machineName"); } catch (Exception e) { } return host; } public String getAdminIP() { return info[ADMIN][IP]; } public String getAdminPort() { return info[ADMIN][PORT]; } public IHttpConnection getHttpConnection(IRemoteAuthority authority, ISocketFactory factory) { return new HttpConnection(authority, factory); } public IHttpConnection getHttpConnection(IRemoteAuthority authority, ISocketFactory factory, int timeout) { return new HttpConnection(authority, factory, timeout); } public IResender getResender(IAuthority authority, String nickname, String clientCiphers, IRemoteAuthority remote, int interval) { return new Resender(authority, nickname, clientCiphers, remote, interval); } public IPKIMessage getHttpPKIMessage() { return new HttpPKIMessage(); } public ILdapConnInfo getLdapConnInfo(IConfigStore config) throws EBaseException, ELdapException { return new LdapConnInfo(config); } public LDAPSSLSocketFactoryExt getLdapJssSSLSocketFactory(String certNickname) { return new PKISocketFactory(certNickname); } public LDAPSSLSocketFactoryExt getLdapJssSSLSocketFactory() { return new PKISocketFactory(true); } public LDAPSocketFactory getLDAPSocketFactory(boolean secure) { return new PKISocketFactory(secure); } public ILdapAuthInfo getLdapAuthInfo() { return new LdapAuthInfo(); } public ILdapConnFactory getLdapBoundConnFactory(String id) throws ELdapException { return new LdapBoundConnFactory(id); } public ILdapConnFactory getLdapAnonConnFactory(String id) throws ELdapException { return new LdapAnonConnFactory(id); } public IRequestEncoder getHttpRequestEncoder() { return new HttpRequestEncoder(); } public Enumeration<String> getSubsystemNames() { return mSSReg.keys(); } public Enumeration<ISubsystem> getSubsystems() { return mSSReg.elements(); } public ISubsystem getSubsystem(String name) { return mSSReg.get(name); } protected void initSubsystems() throws EBaseException { mSSReg.put(ID, this); initSubsystems(staticSubsystems); // Once the log subsystem is initialized, we // want to register a listener to catch // all the warning message so that we can // display them in the console. mQueue = Logger.getLogger().getLogQueue(); mWarningListener = new WarningListener(mWarning); mQueue.addLogEventListener(mWarningListener); initSubsystems(dynSubsystems); initSubsystems(finalSubsystems); } private void initSubsystems(Map<String, SubsystemInfo> subsystems) throws EBaseException { for (SubsystemInfo si : subsystems.values()) { initSubsystem(si); } } private ArrayList<String> getDynSubsystemNames() throws EBaseException { IConfigStore ssconfig = mConfig.getSubStore(PROP_SUBSYSTEM); Enumeration<String> ssNames = ssconfig.getSubStoreNames(); ArrayList<String> ssNamesList = new ArrayList<String>(); while (ssNames.hasMoreElements()) ssNamesList.add(ssNames.nextElement()); return ssNamesList; } /** * load subsystems */ protected void loadSubsystems() throws EBaseException { logger.debug("CMSEngine: loading static subsystems"); staticSubsystems.clear(); staticSubsystems.put(Debug.ID, new SubsystemInfo(Debug.ID, Debug.getInstance())); staticSubsystems.put(LogSubsystem.ID, new SubsystemInfo(LogSubsystem.ID, LogSubsystem.getInstance())); staticSubsystems.put(JssSubsystem.ID, new SubsystemInfo(JssSubsystem.ID, JssSubsystem.getInstance())); staticSubsystems.put(DBSubsystem.ID, new SubsystemInfo(DBSubsystem.ID, DBSubsystem.getInstance())); staticSubsystems.put(UGSubsystem.ID, new SubsystemInfo(UGSubsystem.ID, UGSubsystem.getInstance())); staticSubsystems.put(PluginRegistry.ID, new SubsystemInfo(PluginRegistry.ID, new PluginRegistry())); staticSubsystems.put(OidLoaderSubsystem.ID, new SubsystemInfo(OidLoaderSubsystem.ID, OidLoaderSubsystem.getInstance())); staticSubsystems.put(X500NameSubsystem.ID, new SubsystemInfo(X500NameSubsystem.ID, X500NameSubsystem.getInstance())); // skip TP subsystem; // problem in needing dbsubsystem in constructor. and it's not used. staticSubsystems.put(RequestSubsystem.ID, new SubsystemInfo(RequestSubsystem.ID, RequestSubsystem.getInstance())); logger.debug("CMSEngine: loading dyn subsystems"); dynSubsystems.clear(); ArrayList<String> ssNames = getDynSubsystemNames(); IConfigStore ssconfig = mConfig.getSubStore(PROP_SUBSYSTEM); for (String ssName : ssNames) { IConfigStore config = ssconfig.getSubStore(ssName); String id = config.getString(PROP_ID); String classname = config.getString(PROP_CLASS); boolean enabled = config.getBoolean(PROP_ENABLED, true); ISubsystem ss = null; try { ss = (ISubsystem) Class.forName(classname).newInstance(); } catch (InstantiationException e) { throw new EBaseException(CMS.getUserMessage("CMS_BASE_LOAD_FAILED_1", id, e.toString()), e); } catch (IllegalAccessException e) { throw new EBaseException(CMS.getUserMessage("CMS_BASE_LOAD_FAILED_1", id, e.toString()), e); } catch (ClassNotFoundException e) { throw new EBaseException(CMS.getUserMessage("CMS_BASE_LOAD_FAILED_1", id, e.toString()), e); } dynSubsystems.put(id, new SubsystemInfo(id, ss, enabled, true)); logger.debug("CMSEngine: loaded dyn subsystem " + id); } logger.debug("CMSEngine: loading final subsystems"); finalSubsystems.clear(); finalSubsystems.put(AuthSubsystem.ID, new SubsystemInfo(AuthSubsystem.ID, AuthSubsystem.getInstance())); finalSubsystems.put(AuthzSubsystem.ID, new SubsystemInfo(AuthzSubsystem.ID, AuthzSubsystem.getInstance())); finalSubsystems.put(JobsScheduler.ID, new SubsystemInfo(JobsScheduler.ID, JobsScheduler.getInstance())); if (isPreOpMode()) { // Disable some subsystems before database initialization // in pre-op mode to prevent errors. SubsystemInfo si = staticSubsystems.get(UGSubsystem.ID); si.enabled = false; } } /** * Set whether the given subsystem is enabled. * * @param id The subsystem ID. * @param enabled Whether the subsystem is enabled */ public void setSubsystemEnabled(String id, boolean enabled) throws EBaseException { IConfigStore ssconfig = mConfig.getSubStore(PROP_SUBSYSTEM); for (String ssName : getDynSubsystemNames()) { IConfigStore config = ssconfig.getSubStore(ssName); if (id.equalsIgnoreCase(config.getString(PROP_ID))) { config.putBoolean(PROP_ENABLED, enabled); break; } } } public LDAPConnection getBoundConnection(String id, String host, int port, int version, LDAPSSLSocketFactoryExt fac, String bindDN, String bindPW) throws LDAPException { return new LdapBoundConnection(host, port, version, fac, bindDN, bindPW); } /** * initialize a subsystem */ private void initSubsystem(SubsystemInfo ssinfo) throws EBaseException { String id = ssinfo.id; ISubsystem ss = ssinfo.instance; logger.debug("CMSEngine: initSubsystem(" + id + ")"); mSSReg.put(id, ss); if (ssinfo.updateIdOnInit) { ss.setId(id); } IConfigStore ssConfig = mConfig.getSubStore(id); if (!ssinfo.enabled) { logger.debug("CMSEngine: " + id + " disabled"); return; } logger.debug("CMSEngine: initializing " + id); ss.init(this, ssConfig); try { /* * autoShutdown.allowed=false * autoShutdown.crumbFile=[PKI_INSTANCE_PATH]/logs/autoShutdown.crumb * autoShutdown.restart.enable=false * autoShutdown.restart.max=3 * autoShutdown.restart.count=0 */ mAutoSD_Restart = mConfig.getBoolean("autoShutdown.restart.enable", false); logger.debug("CMSEngine: restart at autoShutdown: " + mAutoSD_Restart); if (mAutoSD_Restart) { mAutoSD_RestartMax = mConfig.getInteger("autoShutdown.restart.max", 3); logger.debug("CMSEngine: restart max: " + mAutoSD_RestartMax); mAutoSD_RestartCount = mConfig.getInteger("autoShutdown.restart.count", 0); logger.debug("CMSEngine: current restart count: " + mAutoSD_RestartCount); } else { //!mAutoSD_Restart mAutoSD_CrumbFile = mConfig.getString("autoShutdown.crumbFile", instanceDir + "/logs/autoShutdown.crumb"); logger.debug("CMSEngine: autoShutdown crumb file path: " + mAutoSD_CrumbFile); File crumb = new File(mAutoSD_CrumbFile); try { if (crumb.exists()) { logger.debug("CMSEngine: delete autoShutdown crumb file"); crumb.delete(); } } catch (Exception e) { logger.warn("Delete autoShutdown crumb file failed: " + e.getMessage(), e); logger.warn("Continue with initialization"); } } /* * establish signing key reference using audit signing cert * for HSM failover detection */ mSAuditCertNickName = mConfig.getString(PROP_SIGNED_AUDIT_CERT_NICKNAME); mManager = CryptoManager.getInstance(); logger.debug("CMSEngine: about to look for cert for auto-shutdown support:" + mSAuditCertNickName); org.mozilla.jss.crypto.X509Certificate cert = null; try { cert = mManager.findCertByNickname(mSAuditCertNickName); } catch (ObjectNotFoundException as) { logger.warn("CMSEngine: Unable to support auto-shutdown: " + as.getMessage()); } if (cert != null) { logger.debug("CMSEngine: found cert:" + mSAuditCertNickName); mSigningKey = mManager.findPrivKeyByCert(cert); mSigningData = cert.getPublicKey().getEncoded(); } } catch (Exception e) { logger.warn("CMSEngine: Unable to configure auto-shutdown: " + e.getMessage(), e); } // add to id - subsystem hash table. logger.debug("CMSEngine: done init id=" + id); logger.debug("CMSEngine: initialized " + id); if (id.equals("ca") || id.equals("ocsp") || id.equals("kra") || id.equals("tks")) { logger.debug("CMSEngine: get SSL server nickname"); IConfigStore serverCertStore = mConfig.getSubStore(id + "." + "sslserver"); if (serverCertStore != null && serverCertStore.size() > 0) { String nickName = serverCertStore.getString("nickname"); String tokenName = serverCertStore.getString("tokenname"); if (tokenName != null && tokenName.length() > 0 && nickName != null && nickName.length() > 0) { setServerCertNickname(tokenName, nickName); logger.debug("Subsystem " + id + " init sslserver: tokenName:" + tokenName + " nickName:" + nickName); } else if (nickName != null && nickName.length() > 0) { setServerCertNickname(nickName); logger.debug("Subsystem " + id + " init sslserver: nickName:" + nickName); } else { logger.warn( "Subsystem " + id + " init error: SSL server certificate nickname is not available."); } } } if (id.equals("ca") || id.equals("kra")) { /* figure out if any ldap attributes need exclusion in enrollment records Default config: excludedLdapAttrs.enabled=false; (excludedLdapAttrs.attrs unspecified to take default) */ mExcludedLdapAttrsEnabled = mConfig.getBoolean("excludedLdapAttrs.enabled", false); if (mExcludedLdapAttrsEnabled == true) { logger.debug("CMSEngine: initSubsystem: excludedLdapAttrs.enabled: true"); excludedLdapAttrsList = Arrays.asList(excludedLdapAttrs); String unparsedExcludedLdapAttrs = ""; try { unparsedExcludedLdapAttrs = mConfig.getString("excludedLdapAttrs.attrs"); logger.debug("CMSEngine: initSubsystem: excludedLdapAttrs.attrs =" + unparsedExcludedLdapAttrs); } catch (Exception e) { logger.debug("CMSEngine: initSubsystem: excludedLdapAttrs.attrs unspecified, taking default"); } if (!unparsedExcludedLdapAttrs.equals("")) { excludedLdapAttrsList = Arrays.asList(unparsedExcludedLdapAttrs.split(",")); // overwrites the default //excludedLdapAttrSet = new HashSet(excludedLdapAttrsList); } } else { logger.debug("CMSEngine: initSubsystem: excludedLdapAttrs.enabled: false"); } } } public boolean isExcludedLdapAttrsEnabled() { return mExcludedLdapAttrsEnabled; } public boolean isExcludedLdapAttr(String key) { if (isExcludedLdapAttrsEnabled()) { return excludedLdapAttrsList.contains(key); } else { return false; } } // default for excludedLdapAttrs.enabled == false // can be overwritten with excludedLdapAttrs.attrs public List<String> excludedLdapAttrsList = new ArrayList<String>(); public static String excludedLdapAttrs[] = { "req_x509info", "publickey", "req_extensions", "cert_request", "req_archive_options", "req_key" }; /** * sign some known data to determine if signing key is botched; * if so, proceed to graceful shutdown */ public void checkForAndAutoShutdown() { String method = "CMSEngine: checkForAndAutoShutdown: "; logger.debug(method + "begins"); try { boolean allowShutdown = mConfig.getBoolean("autoShutdown.allowed", false); if ((!allowShutdown) || (mSigningKey == null) || (mSigningData == null)) { logger.debug(method + "autoShutdown not allowed"); return; } logger.debug(method + "autoShutdown allowed"); CryptoToken token = ((org.mozilla.jss.pkcs11.PK11PrivKey) mSigningKey).getOwningToken(); SignatureAlgorithm signAlg = Cert.mapAlgorithmToJss("SHA256withRSA"); Signature signer = token.getSignatureContext(signAlg); signer.initSign(mSigningKey); signer.update(mSigningData); byte[] result = signer.sign(); logger.debug(method + " signining successful: " + new String(result)); } catch (SignatureException e) { //Let's write to the error console in case we are in a bad memory situation //This will be the most likely to work, giving us a record of the signing failure ConsoleError.send(new SystemEvent(CMS.getUserMessage("CMS_CA_SIGNING_OPERATION_FAILED", e.toString()))); logger.warn(method + "autoShutdown for " + e.getMessage(), e); autoShutdown(); } catch (Exception e) { logger.warn(method + "continue for " + e.getMessage(), e); } logger.debug(method + "passed; continue"); } public void reinit(String id) throws EBaseException { ISubsystem system = getSubsystem(id); IConfigStore cs = mConfig.getSubStore(id); system.init(this, cs); } /** * Starts up all subsystems. subsystems must be initialized. * * @exception EBaseException if any subsystem fails to startup. */ public void startup() throws EBaseException { startupSubsystems(staticSubsystems); startupSubsystems(dynSubsystems); startupSubsystems(finalSubsystems); // global admin servlet. (anywhere else more fit for this ?) mStartupTime = System.currentTimeMillis(); mQueue.removeLogEventListener(mWarningListener); if (!mWarning.toString().equals("")) { logger.warn(Constants.SERVER_STARTUP_WARNING_MESSAGE + mWarning); } // check serial number ranges if a CA/KRA ICertificateAuthority ca = (ICertificateAuthority) getSubsystem("ca"); if ((ca != null) && !isPreOpMode()) { logger.debug("CMSEngine: checking request serial number ranges for the CA"); ca.getRequestQueue().getRequestRepository().checkRanges(); logger.debug("CMSEngine: checking certificate serial number ranges"); ca.getCertificateRepository().checkRanges(); } IKeyRecoveryAuthority kra = (IKeyRecoveryAuthority) getSubsystem("kra"); if ((kra != null) && !isPreOpMode()) { logger.debug("CMSEngine: checking request serial number ranges for the KRA"); kra.getRequestQueue().getRequestRepository().checkRanges(); logger.debug("CMSEngine: checking key serial number ranges"); kra.getKeyRepository().checkRanges(); } /*LogDoc * * @phase server startup * @reason all subsystems are initialized and started. */ logger.info(CMS.getLogMessage("SERVER_STARTUP")); String type = mConfig.get("cs.type"); logger.info(type + " is started."); isStarted = true; } public boolean isInRunningState() { return isStarted; } public byte[] getPKCS7(Locale locale, IRequest req) { try { X509CertImpl cert = req.getExtDataInCert(IEnrollProfile.REQUEST_ISSUED_CERT); if (cert == null) return null; ICertificateAuthority ca = (ICertificateAuthority) getSubsystem("ca"); CertificateChain cachain = ca.getCACertChain(); X509Certificate[] cacerts = cachain.getChain(); X509CertImpl[] userChain = new X509CertImpl[cacerts.length + 1]; int m = 1, n = 0; for (; n < cacerts.length; m++, n++) { userChain[m] = (X509CertImpl) cacerts[n]; } userChain[0] = cert; PKCS7 p7 = new PKCS7(new AlgorithmId[0], new ContentInfo(new byte[0]), userChain, new SignerInfo[0]); ByteArrayOutputStream bos = new ByteArrayOutputStream(); p7.encodeSignedData(bos); return bos.toByteArray(); } catch (Exception e) { return null; } } public String getServerCertNickname() { return mServerCertNickname; } public void setServerCertNickname(String tokenName, String nickName) { String newName = null; if (CryptoUtil.isInternalToken(tokenName)) newName = nickName; else { if (tokenName.equals("") && nickName.equals("")) return; // not sure the logic else newName = tokenName + ":" + nickName; } setServerCertNickname(newName); } public void setServerCertNickname(String newName) { mServerCertNickname = newName; } public String getFingerPrint(Certificate cert) throws CertificateEncodingException, NoSuchAlgorithmException { return CertUtils.getFingerPrint(cert); } public String getFingerPrints(Certificate cert) throws NoSuchAlgorithmException, CertificateEncodingException { return CertUtils.getFingerPrints(cert); } public String getFingerPrints(byte[] certDer) throws NoSuchAlgorithmException { return CertUtils.getFingerPrints(certDer); } public String getUserMessage(Locale locale, String msgID, String params[]) { // if locale is null, try to get it out from session context if (locale == null) { SessionContext sc = SessionContext.getExistingContext(); if (sc != null) locale = (Locale) sc.get(SessionContext.LOCALE); } ResourceBundle rb = null; if (locale == null) { rb = ResourceBundle.getBundle("UserMessages", Locale.ENGLISH); } else { rb = ResourceBundle.getBundle("UserMessages", locale); } String msg = rb.getString(msgID); if (params == null) return msg; MessageFormat mf = new MessageFormat(msg); return mf.format(params); } public String getUserMessage(Locale locale, String msgID) { return getUserMessage(locale, msgID, (String[]) null); } public String getUserMessage(Locale locale, String msgID, String p1) { String params[] = { p1 }; return getUserMessage(locale, msgID, params); } public String getUserMessage(Locale locale, String msgID, String p1, String p2) { String params[] = { p1, p2 }; return getUserMessage(locale, msgID, params); } public String getUserMessage(Locale locale, String msgID, String p1, String p2, String p3) { String params[] = { p1, p2, p3 }; return getUserMessage(locale, msgID, params); } public String getLogMessage(String msgID, Object params[]) { ResourceBundle rb = ResourceBundle.getBundle("LogMessages"); String msg = rb.getString(msgID); if (params == null) return msg; MessageFormat mf = new MessageFormat(msg); Object escapedParams[] = new Object[params.length]; for (int i = 0; i < params.length; i++) { if (params[i] instanceof String) escapedParams[i] = escapeLogMessageParam((String) params[i]); else escapedParams[i] = params[i]; } return mf.format(escapedParams); } /** Quote a string for inclusion in a java.text.MessageFormat */ private String escapeLogMessageParam(String s) { if (s == null) return null; if (s.contains("{") || s.contains("}")) return "'" + s.replaceAll("'", "''") + "'"; return s; } public void debug(byte data[]) { if (!debugOn()) { // this helps to not saving stuff to file when debug // is disable return; } Debug.print(data); } public void debug(int level, String msg) { if (!debugOn()) { // this helps to not saving stuff to file when debug // is disable return; } Debug.trace(level, msg); } public void debug(String msg) { if (!debugOn()) { // this helps to not saving stuff to file when debug // is disable return; } Debug.trace(msg); } public void debug(Throwable e) { if (!debugOn()) { // this helps to not saving stuff to file when debug // is disable return; } Debug.printStackTrace(e); } public boolean debugOn() { return Debug.on(); } public void debugStackTrace() { Debug.printStackTrace(); } public void traceHashKey(String type, String key) { Debug.traceHashKey(type, key); } public void traceHashKey(String type, String key, String val) { Debug.traceHashKey(type, key, val); } public void traceHashKey(String type, String key, String val, String def) { Debug.traceHashKey(type, key, val, def); } public String getLogMessage(String msgID) { return getLogMessage(msgID, (String[]) null); } public String getLogMessage(String msgID, String p1) { String params[] = { p1 }; return getLogMessage(msgID, params); } public String getLogMessage(String msgID, String p1, String p2) { String params[] = { p1, p2 }; return getLogMessage(msgID, params); } public String getLogMessage(String msgID, String p1, String p2, String p3) { String params[] = { p1, p2, p3 }; return getLogMessage(msgID, params); } public String getLogMessage(String msgID, String p1, String p2, String p3, String p4) { String params[] = { p1, p2, p3, p4 }; return getLogMessage(msgID, params); } public String getLogMessage(String msgID, String p1, String p2, String p3, String p4, String p5) { String params[] = { p1, p2, p3, p4, p5 }; return getLogMessage(msgID, params); } public String getLogMessage(String msgID, String p1, String p2, String p3, String p4, String p5, String p6) { String params[] = { p1, p2, p3, p4, p5, p6 }; return getLogMessage(msgID, params); } public String getLogMessage(String msgID, String p1, String p2, String p3, String p4, String p5, String p6, String p7) { String params[] = { p1, p2, p3, p4, p5, p6, p7 }; return getLogMessage(msgID, params); } public String getLogMessage(String msgID, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8) { String params[] = { p1, p2, p3, p4, p5, p6, p7, p8 }; return getLogMessage(msgID, params); } public String getLogMessage(String msgID, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9) { String params[] = { p1, p2, p3, p4, p5, p6, p7, p8, p9 }; return getLogMessage(msgID, params); } public String getLogMessage(String msgID, String p1, String p2, String p3, String p4, String p5, String p6, String p7, String p8, String p9, String p10) { String params[] = { p1, p2, p3, p4, p5, p6, p7, p8, p9, p10 }; return getLogMessage(msgID, params); } public void getSubjAltNameConfigDefaultParams(String name, Vector<String> params) { GeneralNameUtil.SubjAltNameGN.getDefaultParams(name, params); } public void getSubjAltNameConfigExtendedPluginInfo(String name, Vector<String> params) { GeneralNameUtil.SubjAltNameGN.getExtendedPluginInfo(name, params); } public ISubjAltNameConfig createSubjAltNameConfig(String name, IConfigStore config, boolean isValueConfigured) throws EBaseException { return new GeneralNameUtil.SubjAltNameGN(name, config, isValueConfigured); } public GeneralName form_GeneralNameAsConstraints(String generalNameChoice, String value) throws EBaseException { return GeneralNameUtil.form_GeneralNameAsConstraints(generalNameChoice, value); } public GeneralName form_GeneralName(String generalNameChoice, String value) throws EBaseException { return GeneralNameUtil.form_GeneralName(generalNameChoice, value); } public void getGeneralNameConfigDefaultParams(String name, boolean isValueConfigured, Vector<String> params) { GeneralNameUtil.GeneralNameConfig.getDefaultParams(name, isValueConfigured, params); } public void getGeneralNamesConfigDefaultParams(String name, boolean isValueConfigured, Vector<String> params) { GeneralNameUtil.GeneralNamesConfig.getDefaultParams(name, isValueConfigured, params); } public void getGeneralNameConfigExtendedPluginInfo(String name, boolean isValueConfigured, Vector<String> info) { GeneralNameUtil.GeneralNameConfig.getExtendedPluginInfo(name, isValueConfigured, info); } public void getGeneralNamesConfigExtendedPluginInfo(String name, boolean isValueConfigured, Vector<String> info) { GeneralNameUtil.GeneralNamesConfig.getExtendedPluginInfo(name, isValueConfigured, info); } public IGeneralNamesConfig createGeneralNamesConfig(String name, IConfigStore config, boolean isValueConfigured, boolean isPolicyEnabled) throws EBaseException { return new GeneralNameUtil.GeneralNamesConfig(name, config, isValueConfigured, isPolicyEnabled); } public IGeneralNameAsConstraintsConfig createGeneralNameAsConstraintsConfig(String name, IConfigStore config, boolean isValueConfigured, boolean isPolicyEnabled) throws EBaseException { return new GeneralNameUtil.GeneralNameAsConstraintsConfig(name, config, isValueConfigured, isPolicyEnabled); } public IGeneralNamesAsConstraintsConfig createGeneralNamesAsConstraintsConfig(String name, IConfigStore config, boolean isValueConfigured, boolean isPolicyEnabled) throws EBaseException { return new GeneralNameUtil.GeneralNamesAsConstraintsConfig(name, config, isValueConfigured, isPolicyEnabled); } public ObjectIdentifier checkOID(String attrName, String value) throws EBaseException { return CertUtils.checkOID(attrName, value); } public String BtoA(byte data[]) { return Utils.base64encode(data, true); } public byte[] AtoB(String data) { return Utils.base64decode(data); } public String getEncodedCert(X509Certificate cert) { try { return Cert.HEADER + "\n" + Utils.base64encode(cert.getEncoded(), true) + Cert.FOOTER + "\n"; } catch (Exception e) { return null; } } public void verifySystemCerts() throws Exception { CertUtils.verifySystemCerts(); } public void verifySystemCertByTag(String tag) throws Exception { CertUtils.verifySystemCertByTag(tag); } public void verifySystemCertByNickname(String nickname, String certificateUsage) throws Exception { CertUtils.verifySystemCertByNickname(nickname, certificateUsage); } public CertificateUsage getCertificateUsage(String certusage) { return CertUtils.getCertificateUsage(certusage); } public boolean isSigningCert(X509Certificate cert) { return CertUtils.isSigningCert((X509CertImpl) cert); } public boolean isEncryptionCert(X509Certificate cert) { return CertUtils.isEncryptionCert((X509CertImpl) cert); } public X509CertInfo getDefaultX509CertInfo() { return new CertInfo(); } public IEmailResolverKeys getEmailResolverKeys() { return new EmailResolverKeys(); } public IEmailResolver getReqCertSANameEmailResolver() { return new ReqCertSANameEmailResolver(); } public IEmailFormProcessor getEmailFormProcessor() { return new EmailFormProcessor(); } public IEmailTemplate getEmailTemplate(String path) { return new EmailTemplate(path); } public IMailNotification getMailNotification() { try { String className = mConfig.getString("notificationClassName", "com.netscape.cms.notification.MailNotification"); IMailNotification notification = (IMailNotification) Class.forName(className).newInstance(); return notification; } catch (Exception e) { return null; } } public IPrettyPrintFormat getPrettyPrintFormat(String delimiter) { return new com.netscape.cmscore.cert.PrettyPrintFormat(delimiter); } public IExtPrettyPrint getExtPrettyPrint(Extension e, int indent) { return new ExtPrettyPrint(e, indent); } public ICertPrettyPrint getCertPrettyPrint(X509Certificate cert) { return new CertPrettyPrint(cert); } public ICRLPrettyPrint getCRLPrettyPrint(X509CRL crl) { return new CrlPrettyPrint((X509CRLImpl) crl); } public ICRLPrettyPrint getCRLCachePrettyPrint(ICRLIssuingPoint ip) { return new CrlCachePrettyPrint(ip); } public IPasswordCheck getPasswordChecker() { try { String className = mConfig.getString("passwordCheckerClass", "com.netscape.cms.password.PasswordChecker"); IPasswordCheck check = (IPasswordCheck) Class.forName(className).newInstance(); return check; } catch (Exception e) { return null; } } public ISharedToken getSharedTokenClass(String configName) { String method = "CMSEngine: getSharedTokenClass: "; ISharedToken tokenClass = null; String name = null; try { logger.debug(method + "getting :" + configName); name = getConfigStore().getString(configName); logger.debug(method + "Shared Secret plugin class name retrieved:" + name); } catch (Exception e) { logger.warn(method + " Failed to retrieve shared secret plugin class name"); return null; } try { tokenClass = (ISharedToken) Class.forName(name).newInstance(); logger.debug(method + "Shared Secret plugin class retrieved"); } catch (ClassNotFoundException e) { logger.warn(method + " Failed to find class name: " + name); return null; } catch (InstantiationException e) { logger.warn("EnrollProfile: Failed to instantiate class: " + name); return null; } catch (IllegalAccessException e) { logger.warn(method + " Illegal access: " + name); return null; } return tokenClass; } public ILogger getLogger() { return Logger.getLogger(); } public IAuditor getAuditor() { return Auditor.getAuditor(); } private void startupSubsystems(Map<String, SubsystemInfo> subsystems) throws EBaseException { for (SubsystemInfo si : subsystems.values()) { logger.debug("CMSEngine: starting " + si.id); si.instance.startup(); logger.debug("CMSEngine: " + si.id + " started"); } } public void disableRequests() { CommandQueue.mShuttingDown = true; } public boolean areRequestsDisabled() { logger.debug("CMSEngine: in areRequestsDisabled"); return CommandQueue.mShuttingDown; } public void terminateRequests() { Enumeration<ICMSRequest> e = CommandQueue.mCommandQueue.keys(); while (e.hasMoreElements()) { Object thisRequest = e.nextElement(); HttpServlet thisServlet = (HttpServlet) CommandQueue.mCommandQueue.get(thisRequest); if (thisServlet != null) { CommandQueue.mCommandQueue.remove(thisRequest); thisServlet.destroy(); } } } public static boolean isNT() { return (File.separator.equals("\\")); } private void shutdownHttpServer(boolean restart) { try { String cmds[] = null; String cmd = "stop"; if (restart) { cmd = "restart"; } cmds = new String[3]; cmds[0] = "/usr/bin/systemctl"; cmds[1] = cmd; if (startedByNuxwdog()) { cmds[2] = "pki-tomcatd-nuxwdog@" + instanceId + ".service"; } else { cmds[2] = "pki-tomcatd@" + instanceId + ".service"; } Process process = Runtime.getRuntime().exec(cmds); process.waitFor(); } catch (IOException e) { logger.warn("Unable to shutdown HTTP server: " + e.getMessage(), e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } // end shutdownHttpServer /** * Shuts down subsystems in backwards order * exceptions are ignored. process exists at end to force exit. */ public void shutdown() { logger.info("Shutting down"); /* CommandQueue commandQueue = new CommandQueue(); Thread t1 = new Thread(commandQueue); t1.setDaemon(true); t1.start(); // wait for command queue to emptied before proceeding to shutting down subsystems Date time = new Date(); long startTime = time.getTime(); long timeOut = time.getTime(); while (t1.isAlive() && ((timeOut - startTime) < (60 * 1000))) //wait for 1 minute { try { Thread.currentThread().sleep(5000); // sleep for 5 sec }catch (java.lang.InterruptedException e) { } timeOut = time.getTime(); } terminateRequests(); */ shutdownSubsystems(finalSubsystems); shutdownSubsystems(dynSubsystems); shutdownSubsystems(staticSubsystems); if (mSDTimer != null) { mSDTimer.cancel(); } if (mSecurityDomainSessionTable != null) { mSecurityDomainSessionTable.shutdown(); } } /** * Shuts down subsystems in backwards order * exceptions are ignored. process exists at end to force exit. * Added extra call to shutdown the web server. */ public void forceShutdown() { logger.debug("CMSEngine.forceShutdown()...begins graceful shutdown."); autoShutdown(false /*no restart*/); } public void autoShutdown() { autoShutdown(mAutoSD_Restart /* controlled by config */); } public void autoShutdown(boolean restart) { logger.info("Shutting down"); logger.debug("CMSEngine: restart: " + restart); // update restart tracker so we don't go into infinite restart loop if (restart) { logger.debug("CMSEngine: checking autoShutdown.restart trackers"); if (mAutoSD_RestartCount >= mAutoSD_RestartMax) { mAutoSD_Restart = false; mConfig.putBoolean("autoShutdown.restart.enable", mAutoSD_Restart); logger.debug("CMSEngine: autoShutdown.restart.max reached, disabled autoShutdown.restart.enable"); } else { mAutoSD_RestartCount++; mConfig.putInteger("autoShutdown.restart.count", mAutoSD_RestartCount); logger.debug( "CMSEngine: autoShutdown.restart.max not reached, increment autoShutdown.restart.count"); } try { mConfig.commit(false); } catch (EBaseException e) { logger.warn("Unable to store configuration: " + e.getMessage(), e); } } else { // leave a crumb file to be monitored by external monitor File crumb = new File(mAutoSD_CrumbFile); try { crumb.createNewFile(); } catch (IOException e) { logger.warn("Create autoShutdown crumb file failed on " + mAutoSD_CrumbFile + ": " + e.getMessage(), e); logger.warn("Nothing to do, keep shutting down"); } } /* cfu: not sure why it's doing a commandQueue but not registering any * service to wait on... what does this do to wait on an empty queue? * CommandQueue commandQueue = new CommandQueue(); Thread t1 = new Thread(commandQueue); t1.setDaemon(true); t1.start(); // wait for command queue to emptied before proceeding to shutting down subsystems Date time = new Date(); long startTime = time.getTime(); long timeOut = time.getTime(); while (t1.isAlive() && ((timeOut - startTime) < (60 * 1000))) //wait for 1 minute { try { Thread.sleep(5000); // sleep for 5 sec } catch (java.lang.InterruptedException e) { } timeOut = time.getTime(); } */ if (areRequestsDisabled() == false) { disableRequests(); } terminateRequests(); shutdownSubsystems(finalSubsystems); shutdownSubsystems(dynSubsystems); shutdownSubsystems(staticSubsystems); shutdownHttpServer(restart); } private void shutdownSubsystems(Map<String, SubsystemInfo> subsystems) { // reverse list of subsystems List<SubsystemInfo> list = new ArrayList<>(subsystems.values()); Collections.reverse(list); for (SubsystemInfo si : list) { logger.debug("CMSEngine: stopping " + si.id); si.instance.shutdown(); logger.debug("CMSEngine: " + si.id + " stopped"); } } /** * returns the main config store */ public IConfigStore getConfigStore() { return mConfig; } /** * get time server started up */ public long getStartupTime() { return mStartupTime; } public void putPasswordCache(String tag, String pw) { try { PWsdrCache pwc = new PWsdrCache(); pwc.addEntry(tag, pw); } catch (EBaseException e) { // intercept this for now -- don't want to change the callers logger.warn(CMS.getLogMessage("CMSCORE_SDR_ADD_ERROR", e.toString()), e); } } public PasswordCallback getPasswordCallback() { return new PWCBsdr(); } public int getPID() { if (pid != 0) return pid; BufferedReader bf = null; try { // PID file is be created by wrapper script (e.g. /usr/sbin/tomcat6) // The default is for dogtag 9 systems which did not have this paramater String dir = mConfig.getString("pidDir", "/var/run"); String name = dir + File.separator + instanceId + ".pid"; if (dir == null) return pid; File file = new File(name); if (!file.exists()) return pid; bf = new BufferedReader(new FileReader(file)); String value = bf.readLine(); pid = Integer.parseInt(value); } catch (Exception e) { logger.warn("Unable to get PID: " + e.getMessage(), e); } finally { try { if (bf != null) bf.close(); } catch (Exception e) { logger.warn("Unable to close BufferedReader: " + e.getMessage(), e); } } return pid; } public Date getCurrentDate() { if (mTimeSource == null) { return new Date(); } return mTimeSource.getCurrentDate(); } public void setConfigSDSessionId(String val) { mConfigSDSessionId = val; } public String getConfigSDSessionId() { return mConfigSDSessionId; } public static void upgradeConfig(IConfigStore c) throws EBaseException { String version = c.getString("cms.version", "pre4.2"); if (version.equals("4.22")) { Upgrade.perform422to45(c); } else if (version.equals("4.2")) { // SUPPORT UPGRADE FROM 4.2 to 4.2 (SP2) Upgrade.perform42to422(c); Upgrade.perform422to45(c); } else { // ONLY SUPPORT UPGRADE FROM 4.2 to 4.2 (SP2) /** * if (!version.equals("pre4.2")) * return; * * Upgrade.perform(c); **/ } } public ICommandQueue getCommandQueue() { return new CommandQueue(); } private ICertificateRepository getCertDB() { ICertificateRepository certDB = null; try { ICertificateAuthority ca = (ICertificateAuthority) SubsystemRegistry.getInstance().get("ca"); if (ca != null) { certDB = ca.getCertificateRepository(); } } catch (Exception e) { logger.warn("CMSEngine: " + CMS.getLogMessage("CMSCORE_AUTH_AGENT_CERT_REPO")); } return certDB; } private IRequestQueue getReqQueue() { IRequestQueue queue = null; try { IRegistrationAuthority ra = (IRegistrationAuthority) SubsystemRegistry.getInstance().get("ra"); if (ra != null) { queue = ra.getRequestQueue(); } } catch (Exception e) { logger.warn(CMS.getLogMessage("CMSCORE_AUTH_AGENT_REQUEST_QUEUE"), e); } return queue; } private VerifiedCerts mVCList = null; private int mVCListSize = 0; public void setListOfVerifiedCerts(int size, long interval, long unknownStateInterval) { if (size > 0 && mVCListSize == 0) { mVCListSize = size; mVCList = new VerifiedCerts(size, interval, unknownStateInterval); } } public boolean isRevoked(X509Certificate[] certificates) { boolean revoked = false; if (certificates != null) { X509CertImpl cert = (X509CertImpl) certificates[0]; int result = VerifiedCert.UNKNOWN; if (mVCList != null) { result = mVCList.check(cert); } if (result != VerifiedCert.REVOKED && result != VerifiedCert.NOT_REVOKED && result != VerifiedCert.CHECKED) { CertificateRepository certDB = (CertificateRepository) getCertDB(); if (certDB != null) { try { if (certDB.isCertificateRevoked(cert) != null) { revoked = true; if (mVCList != null) mVCList.update(cert, VerifiedCert.REVOKED); } else { if (mVCList != null) mVCList.update(cert, VerifiedCert.NOT_REVOKED); } } catch (EBaseException e) { logger.warn(CMS.getLogMessage("CMSCORE_AUTH_AGENT_REVO_STATUS"), e); } } else { IRequestQueue queue = getReqQueue(); if (queue != null) { IRequest checkRevReq = null; try { checkRevReq = queue.newRequest(CertRequestConstants.GETREVOCATIONINFO_REQUEST); checkRevReq.setExtData(IRequest.REQ_TYPE, CertRequestConstants.GETREVOCATIONINFO_REQUEST); checkRevReq.setExtData(IRequest.REQUESTOR_TYPE, IRequest.REQUESTOR_RA); X509CertImpl agentCerts[] = new X509CertImpl[certificates.length]; for (int i = 0; i < certificates.length; i++) { agentCerts[i] = (X509CertImpl) certificates[i]; } checkRevReq.setExtData(IRequest.ISSUED_CERTS, agentCerts); queue.processRequest(checkRevReq); RequestStatus status = checkRevReq.getRequestStatus(); if (status == RequestStatus.COMPLETE) { Enumeration<String> enum1 = checkRevReq.getExtDataKeys(); while (enum1.hasMoreElements()) { String name = enum1.nextElement(); if (name.equals(IRequest.REVOKED_CERTS)) { revoked = true; if (mVCList != null) mVCList.update(cert, VerifiedCert.REVOKED); } } if (revoked == false) { if (mVCList != null) mVCList.update(cert, VerifiedCert.NOT_REVOKED); } } else { if (mVCList != null) mVCList.update(cert, VerifiedCert.CHECKED); } } catch (EBaseException e) { logger.warn(CMS.getLogMessage("CMSCORE_AUTH_AGENT_PROCESS_CHECKING"), e); } } } } else if (result == VerifiedCert.REVOKED) { revoked = true; } } return revoked; } @Override public String getServerStatus() { return serverStatus; } // for debug only public void sleepOneMinute() { boolean debugSleep = false; try { debugSleep = mConfig.getBoolean("debug.sleepOneMinute", false); } catch (Exception e) { } /* debugSleep: sleep for one minute to check something, e.g. ldap*/ if (debugSleep == true) { logger.debug("debugSleep: about to sleep for one minute; do check now: e.g. ldap, hsm, etc."); try { Thread.sleep(60000); } catch (InterruptedException e) { logger.warn("debugSleep: sleep out:" + e.toString()); } } } } class WarningListener implements ILogEventListener { private StringBuffer mSB = null; public WarningListener(StringBuffer sb) { mSB = sb; } public void log(ILogEvent event) throws ELogException { String str = event.toString(); // start.cc and restart.cc does not like carriage // return. They are the programs that pass the // log messages to the console str = str.replace('\n', ' '); if (event.getLevel() == ILogger.LL_FAILURE) { mSB.append("FAILURE: " + str + "|"); } if (event.getLevel() == ILogger.LL_WARN) { mSB.append("WARNING: " + str + "|"); } } public void flush() { } public void shutdown() { } public IConfigStore getConfigStore() { return null; } public void init(ISubsystem owner, IConfigStore config) throws EBaseException { } public void startup() { } /** * Retrieve last "maxLine" number of system log with log lever >"level" * and from source "source". If the parameter is omitted. All entries * are sent back. */ public synchronized NameValuePairs retrieveLogContent(Hashtable<String, String> req) throws ServletException, IOException, EBaseException { return null; } /** * Retrieve log file list. */ public synchronized NameValuePairs retrieveLogList(Hashtable<String, String> req) throws ServletException, IOException, EBaseException { return null; } public String getImplName() { return "ConsoleLog"; } public String getDescription() { return "ConsoleLog"; } public Vector<String> getDefaultParams() { Vector<String> v = new Vector<String>(); return v; } public Vector<String> getInstanceParams() { Vector<String> v = new Vector<String>(); return v; } }