/* * * Copyright (c) 2013 - 2017 Lijun Liao * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License version 3 * as published by the Free Software Foundation with the addition of the * following permission added to Section 15 as permitted in Section 7(a): * * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY * THE AUTHOR LIJUN LIAO. LIJUN LIAO DISCLAIMS THE WARRANTY OF NON INFRINGEMENT * OF THIRD PARTY RIGHTS. * * 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU Affero General Public License. * * You can be released from the requirements of the license by purchasing * a commercial license. Buying such a license is mandatory as soon as you * develop commercial activities involving the XiPKI software without * disclosing the source code of your own applications. * * For more information, please contact Lijun Liao at this * address: lijun.liao@gmail.com */ package org.xipki.pki.ca.server.impl; import java.io.BufferedOutputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.math.BigInteger; import java.net.SocketException; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.sql.Connection; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.zip.Deflater; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import javax.xml.bind.JAXBException; import org.bouncycastle.asn1.ASN1Set; import org.bouncycastle.asn1.pkcs.Attribute; import org.bouncycastle.asn1.pkcs.CertificationRequest; import org.bouncycastle.asn1.pkcs.CertificationRequestInfo; import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.Extensions; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.util.encoders.Base64; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xipki.commons.audit.AuditEvent; import org.xipki.commons.audit.AuditLevel; import org.xipki.commons.audit.AuditServiceRegister; import org.xipki.commons.audit.AuditStatus; import org.xipki.commons.audit.PciAuditEvent; import org.xipki.commons.common.ConfPairs; import org.xipki.commons.common.InvalidConfException; import org.xipki.commons.common.ObjectCreationException; import org.xipki.commons.common.util.CollectionUtil; import org.xipki.commons.common.util.DateUtil; import org.xipki.commons.common.util.IoUtil; import org.xipki.commons.common.util.LogUtil; import org.xipki.commons.common.util.ParamUtil; import org.xipki.commons.common.util.StringUtil; import org.xipki.commons.datasource.DataSourceFactory; import org.xipki.commons.datasource.DataSourceWrapper; import org.xipki.commons.datasource.springframework.dao.DataAccessException; import org.xipki.commons.password.PasswordResolverException; import org.xipki.commons.security.CertRevocationInfo; import org.xipki.commons.security.ConcurrentContentSigner; import org.xipki.commons.security.CrlReason; import org.xipki.commons.security.SecurityFactory; import org.xipki.commons.security.SignerConf; import org.xipki.commons.security.exception.XiSecurityException; import org.xipki.pki.ca.api.DfltEnvParameterResolver; import org.xipki.pki.ca.api.EnvParameterResolver; import org.xipki.pki.ca.api.NameId; import org.xipki.pki.ca.api.OperationException; import org.xipki.pki.ca.api.OperationException.ErrorCode; import org.xipki.pki.ca.api.RequestType; import org.xipki.pki.ca.api.profile.CertValidity; import org.xipki.pki.ca.api.profile.CertValidity.Unit; import org.xipki.pki.ca.api.profile.CertprofileException; import org.xipki.pki.ca.api.profile.x509.X509Certprofile; import org.xipki.pki.ca.api.profile.x509.X509CertprofileFactoryRegister; import org.xipki.pki.ca.api.publisher.CertPublisherException; import org.xipki.pki.ca.api.publisher.x509.X509CertPublisher; import org.xipki.pki.ca.api.publisher.x509.X509CertPublisherFactoryRegister; import org.xipki.pki.ca.api.publisher.x509.X509CertificateInfo; import org.xipki.pki.ca.server.impl.X509SelfSignedCertBuilder.GenerateSelfSignedResult; import org.xipki.pki.ca.server.impl.cmp.CmpRequestorEntryWrapper; import org.xipki.pki.ca.server.impl.cmp.CmpResponderEntryWrapper; import org.xipki.pki.ca.server.impl.cmp.CmpResponderManager; import org.xipki.pki.ca.server.impl.cmp.X509CaCmpResponder; import org.xipki.pki.ca.server.impl.ocsp.OcspCertPublisher; import org.xipki.pki.ca.server.impl.scep.Scep; import org.xipki.pki.ca.server.impl.scep.ScepManager; import org.xipki.pki.ca.server.impl.store.CertificateStore; import org.xipki.pki.ca.server.impl.store.X509CertWithRevocationInfo; import org.xipki.pki.ca.server.mgmt.api.AddUserEntry; import org.xipki.pki.ca.server.mgmt.api.CaEntry; import org.xipki.pki.ca.server.mgmt.api.CaHasRequestorEntry; import org.xipki.pki.ca.server.mgmt.api.CaHasUserEntry; import org.xipki.pki.ca.server.mgmt.api.CaManager; import org.xipki.pki.ca.server.mgmt.api.CaMgmtException; import org.xipki.pki.ca.server.mgmt.api.CaStatus; import org.xipki.pki.ca.server.mgmt.api.CaSystemStatus; import org.xipki.pki.ca.server.mgmt.api.CertListInfo; import org.xipki.pki.ca.server.mgmt.api.CertListOrderBy; import org.xipki.pki.ca.server.mgmt.api.CertprofileEntry; import org.xipki.pki.ca.server.mgmt.api.ChangeCaEntry; import org.xipki.pki.ca.server.mgmt.api.ChangeUserEntry; import org.xipki.pki.ca.server.mgmt.api.CmpControl; import org.xipki.pki.ca.server.mgmt.api.CmpControlEntry; import org.xipki.pki.ca.server.mgmt.api.CmpRequestorEntry; import org.xipki.pki.ca.server.mgmt.api.CmpResponderEntry; import org.xipki.pki.ca.server.mgmt.api.PublisherEntry; import org.xipki.pki.ca.server.mgmt.api.RequestorInfo; import org.xipki.pki.ca.server.mgmt.api.UserEntry; import org.xipki.pki.ca.server.mgmt.api.conf.CaConf; import org.xipki.pki.ca.server.mgmt.api.conf.GenSelfIssued; import org.xipki.pki.ca.server.mgmt.api.conf.SingleCaConf; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.CAConfType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.CaHasRequestorType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.CaType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.CmpcontrolType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.CrlsignerType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.FileOrBinaryType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.FileOrValueType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.NameValueType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.ProfileType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.PublisherType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.RequestorType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.ResponderType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.ScepType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.StringsType; import org.xipki.pki.ca.server.mgmt.api.conf.jaxb.X509CaInfoType; import org.xipki.pki.ca.server.mgmt.api.x509.CertWithStatusInfo; import org.xipki.pki.ca.server.mgmt.api.x509.ChangeScepEntry; import org.xipki.pki.ca.server.mgmt.api.x509.RevokeSuspendedCertsControl; import org.xipki.pki.ca.server.mgmt.api.x509.ScepEntry; import org.xipki.pki.ca.server.mgmt.api.x509.X509CaEntry; import org.xipki.pki.ca.server.mgmt.api.x509.X509CaUris; import org.xipki.pki.ca.server.mgmt.api.x509.X509ChangeCrlSignerEntry; import org.xipki.pki.ca.server.mgmt.api.x509.X509CrlSignerEntry; import org.xml.sax.SAXException; /** * @author Lijun Liao * @since 2.0.0 */ public class CaManagerImpl implements CaManager, CmpResponderManager, ScepManager { private class CertsInQueuePublisher implements Runnable { private boolean inProcess; @Override public void run() { if (inProcess || !caSystemSetuped) { return; } inProcess = true; try { LOG.debug("publishing certificates in PUBLISHQUEUE"); for (String name : x509cas.keySet()) { X509Ca ca = x509cas.get(name); boolean bo = ca.publishCertsInQueue(); if (bo) { LOG.info(" published certificates of CA {} in PUBLISHQUEUE", name); } else { LOG.error("publishing certificates of CA {} in PUBLISHQUEUE failed", name); } } } catch (Throwable th) { LogUtil.error(LOG, th, "could not publish CertsInQueue"); } finally { inProcess = false; } } // method run } // class ScheduledPublishQueueCleaner private class UnreferencedRequstCleaner implements Runnable { private boolean inProcess; @Override public void run() { if (inProcess) { return; } inProcess = true; try { try { certstore.deleteUnreferencedRequests(); LOG.info("deleted unreferenced requests"); } catch (Throwable th) { LogUtil.error(LOG, th, "could not delete unreferenced requests"); } } finally { inProcess = false; } } // method run } // class ScheduledDeleteUnreferencedRequstervice private class CaRestarter implements Runnable { private boolean inProcess; @Override public void run() { if (inProcess) { return; } inProcess = true; try { SystemEvent event = queryExecutor.getSystemEvent(EVENT_CACHAGNE); long caChangedTime = (event == null) ? 0 : event.getEventTime(); LOG.info("check the restart CA system event: changed at={}, lastStartTime={}", new Date(caChangedTime * 1000L), lastStartTime); if (caChangedTime > lastStartTime.getTime() / 1000L) { LOG.info("received event to restart CA"); restartCaSystem(); } else { LOG.debug("received no event to restart CA"); } } catch (Throwable th) { LogUtil.error(LOG, th, "ScheduledCaRestarter"); } finally { inProcess = false; } } // method run } // class ScheduledCaRestarter public static final String ENV_EPOCH = "EPOCH"; private static final Logger LOG = LoggerFactory.getLogger(CaManagerImpl.class); private static final String EVENT_LOCK = "LOCK"; private static final String EVENT_CACHAGNE = "CA_CHANGE"; private final String lockInstanceId; private final CaIdNameMap idNameMap = new CaIdNameMap(); private ByCaRequestorInfo byCaRequestor; private NameId byUserRequestorId; private boolean caLockedByMe; private boolean masterMode; private Map<String, DataSourceWrapper> datasources; private final Map<String, X509CaInfo> caInfos = new ConcurrentHashMap<>(); private Map<String, CmpResponderEntryWrapper> responders = new ConcurrentHashMap<>(); private Map<String, CmpResponderEntry> responderDbEntries = new ConcurrentHashMap<>(); private final Map<String, IdentifiedX509Certprofile> certprofiles = new ConcurrentHashMap<>(); private final Map<String, CertprofileEntry> certprofileDbEntries = new ConcurrentHashMap<>(); private final Map<String, IdentifiedX509CertPublisher> publishers = new ConcurrentHashMap<>(); private final Map<String, PublisherEntry> publisherDbEntries = new ConcurrentHashMap<>(); private final Map<String, CmpControl> cmpControls = new ConcurrentHashMap<>(); private final Map<String, CmpControlEntry> cmpControlDbEntries = new ConcurrentHashMap<>(); private final Map<String, CmpRequestorEntryWrapper> requestors = new ConcurrentHashMap<>(); private final Map<String, CmpRequestorEntry> requestorDbEntries = new ConcurrentHashMap<>(); private final Map<String, X509CrlSignerEntryWrapper> crlSigners = new ConcurrentHashMap<>(); private final Map<String, X509CrlSignerEntry> crlSignerDbEntries = new ConcurrentHashMap<>(); private final Map<String, Scep> sceps = new ConcurrentHashMap<>(); private final Map<String, ScepEntry> scepDbEntries = new ConcurrentHashMap<>(); private final Map<String, Set<String>> caHasProfiles = new ConcurrentHashMap<>(); private final Map<String, Set<String>> caHasPublishers = new ConcurrentHashMap<>(); private final Map<String, Set<CaHasRequestorEntry>> caHasRequestors = new ConcurrentHashMap<>(); private final Map<String, Integer> caAliases = new ConcurrentHashMap<>(); private final DfltEnvParameterResolver envParameterResolver = new DfltEnvParameterResolver(); private ScheduledThreadPoolExecutor persistentScheduledThreadPoolExecutor; private ScheduledThreadPoolExecutor scheduledThreadPoolExecutor; private final Map<String, X509CaCmpResponder> x509Responders = new ConcurrentHashMap<>(); private final Map<String, X509Ca> x509cas = new ConcurrentHashMap<>(); private final DataSourceFactory datasourceFactory; private String caConfFile; private boolean caSystemSetuped; private boolean responderInitialized; private boolean requestorsInitialized; private boolean caAliasesInitialized; private boolean certprofilesInitialized; private boolean publishersInitialized; private boolean crlSignersInitialized; private boolean cmpControlInitialized; private boolean casInitialized; private boolean environmentParametersInitialized; private boolean scepsInitialized; private Date lastStartTime; private AuditServiceRegister auditServiceRegister; private X509CertprofileFactoryRegister x509CertProfileFactoryRegister; private X509CertPublisherFactoryRegister x509CertPublisherFactoryRegister; private DataSourceWrapper datasource; private CertificateStore certstore; private SecurityFactory securityFactory; private CaManagerQueryExecutor queryExecutor; private boolean initializing; public CaManagerImpl() throws InvalidConfException { this.datasourceFactory = new DataSourceFactory(); String calockId = null; File caLockFile = new File("calock"); if (caLockFile.exists()) { try { calockId = new String(IoUtil.read(caLockFile)); } catch (IOException ex) { LOG.error("could not read {}: {}", caLockFile.getName(), ex.getMessage()); } } if (calockId == null) { calockId = UUID.randomUUID().toString(); try { IoUtil.save(caLockFile, calockId.getBytes()); } catch (IOException ex) { LOG.error("could not save {}: {}", caLockFile.getName(), ex.getMessage()); } } String hostAddress = null; try { hostAddress = IoUtil.getHostAddress(); } catch (SocketException ex) { LOG.warn("could not get host address: {}", ex.getMessage()); } this.lockInstanceId = (hostAddress == null) ? calockId : hostAddress + "/" + calockId; } // constructor public SecurityFactory getSecurityFactory() { return securityFactory; } public void setSecurityFactory(final SecurityFactory securityFactory) { this.securityFactory = securityFactory; } public DataSourceFactory getDataSourceFactory() { return datasourceFactory; } public boolean isMasterMode() { return masterMode; } private void init() throws CaMgmtException { if (securityFactory == null) { throw new IllegalStateException("securityFactory is not set"); } if (datasourceFactory == null) { throw new IllegalStateException("datasourceFactory is not set"); } if (x509CertProfileFactoryRegister == null) { throw new IllegalStateException("x509CertProfileFactoryRegister is not set"); } if (x509CertPublisherFactoryRegister == null) { throw new IllegalStateException("x509CertPublisherFactoryRegister is not set"); } if (caConfFile == null) { throw new IllegalStateException("caConfFile is not set"); } Properties caConfProps = new Properties(); try { caConfProps.load(new FileInputStream(IoUtil.expandFilepath(caConfFile))); } catch (IOException ex) { throw new CaMgmtException("could not parse CA configuration" + caConfFile, ex); } String caModeStr = caConfProps.getProperty("ca.mode"); if (caModeStr != null) { if ("slave".equalsIgnoreCase(caModeStr)) { masterMode = false; } else if ("master".equalsIgnoreCase(caModeStr)) { masterMode = true; } else { throw new CaMgmtException("invalid ca.mode '" + caModeStr + "'"); } } else { masterMode = true; } int shardId; String shardIdStr = caConfProps.getProperty("ca.shardId"); if (StringUtil.isBlank(shardIdStr)) { throw new CaMgmtException("ca.shardId is not set"); } LOG.info("ca.shardId: {}", shardIdStr); try { shardId = Integer.parseInt(shardIdStr); } catch (NumberFormatException ex) { throw new CaMgmtException("invalid ca.shardId '" + shardIdStr + "'"); } if (shardId < 0 || shardId > 127) { throw new CaMgmtException("ca.shardId is not in [0, 127]"); } if (this.datasources == null) { this.datasources = new ConcurrentHashMap<>(); for (Object objKey : caConfProps.keySet()) { String key = (String) objKey; if (!StringUtil.startsWithIgnoreCase(key, "datasource.")) { continue; } String datasourceFile = caConfProps.getProperty(key); try { String datasourceName = key.substring("datasource.".length()); DataSourceWrapper datasource = datasourceFactory.createDataSourceForFile( datasourceName, datasourceFile, securityFactory.getPasswordResolver()); Connection conn = datasource.getConnection(); datasource.returnConnection(conn); this.datasources.put(datasourceName, datasource); } catch (DataAccessException | PasswordResolverException | IOException | RuntimeException ex) { throw new CaMgmtException(ex.getClass().getName() + " while parsing datasource " + datasourceFile, ex); } } this.datasource = this.datasources.get("ca"); } if (this.datasource == null) { throw new CaMgmtException("no datasource named 'ca' configured"); } this.queryExecutor = new CaManagerQueryExecutor(this.datasource); initEnvironmentParamters(); String envEpoch = envParameterResolver.getEnvParam(ENV_EPOCH); if (masterMode) { boolean lockedSuccessful; try { lockedSuccessful = lockCa(true); } catch (DataAccessException ex) { throw new CaMgmtException("DataAccessException while locking CA", ex); } if (!lockedSuccessful) { final String msg = "could not lock the CA database. In general this indicates that another" + " CA software in active mode is accessing the database or the last" + " shutdown of CA software in active mode is abnormal."; throw new CaMgmtException(msg); } if (envEpoch == null) { final long day = 24L * 60 * 60 * 1000; envEpoch = queryExecutor.setEpoch(new Date(System.currentTimeMillis() - day)); LOG.info("set environment {} to {}", ENV_EPOCH, envEpoch); } queryExecutor.addRequestorIfNeeded(RequestorInfo.NAME_BY_CA); queryExecutor.addRequestorIfNeeded(RequestorInfo.NAME_BY_USER); } else { if (envEpoch == null) { throw new CaMgmtException( "The CA system must be started first with ca.mode = master"); } } LOG.info("use EPOCH: {}", envEpoch); long epoch = DateUtil.parseUtcTimeyyyyMMdd(envEpoch).getTime(); UniqueIdGenerator idGen = new UniqueIdGenerator(epoch, shardId); try { this.certstore = new CertificateStore(datasource, idGen); } catch (DataAccessException ex) { throw new CaMgmtException(ex.getMessage(), ex); } initCaAliases(); initCertprofiles(); initPublishers(); initCmpControls(); initRequestors(); initResponders(); initCrlSigners(); initCas(); initSceps(); } // method init @Override public CaSystemStatus getCaSystemStatus() { if (caSystemSetuped) { return masterMode ? CaSystemStatus.STARTED_AS_MASTER : CaSystemStatus.STARTED_AS_SLAVE; } else if (initializing) { return CaSystemStatus.INITIALIZING; } else if (!caLockedByMe) { return CaSystemStatus.LOCK_FAILED; } else { return CaSystemStatus.ERROR; } } private boolean lockCa(final boolean forceRelock) throws DataAccessException, CaMgmtException { SystemEvent lockInfo = queryExecutor.getSystemEvent(EVENT_LOCK); if (lockInfo != null) { String lockedBy = lockInfo.getOwner(); Date lockedAt = new Date(lockInfo.getEventTime() * 1000L); if (!this.lockInstanceId.equals(lockedBy)) { LOG.error("could not lock CA, it has been locked by {} since {}", lockedBy, lockedAt); return false; } if (!forceRelock) { return true; } else { LOG.info("CA has been locked by me since {}, re-lock it", lockedAt); } } SystemEvent newLockInfo = new SystemEvent(EVENT_LOCK, lockInstanceId, System.currentTimeMillis() / 1000L); return queryExecutor.changeSystemEvent(newLockInfo); } // method lockCa @Override public boolean unlockCa() { if (!masterMode) { LOG.error("could not unlock CA in slave mode"); return false; } caLockedByMe = false; boolean successful = false; try { queryExecutor.unlockCa(); successful = true; } catch (CaMgmtException ex) { LogUtil.warn(LOG, ex, "error in unlockCa()"); } if (successful) { LOG.info("unlocked CA"); } else { LOG.error("unlocking CA failed"); } auditLogPciEvent(successful, "UNLOCK"); return successful; } // method unlockCa private void reset() { caSystemSetuped = false; responderInitialized = false; requestorsInitialized = false; caAliasesInitialized = false; certprofilesInitialized = false; publishersInitialized = false; crlSignersInitialized = false; cmpControlInitialized = false; casInitialized = false; environmentParametersInitialized = false; scepsInitialized = false; shutdownScheduledThreadPoolExecutor(); } // method reset @Override public boolean restartCaSystem() { reset(); boolean caSystemStarted = doStartCaSystem(); if (!caSystemStarted) { String msg = "could not restart CA system"; LOG.error(msg); } auditLogPciEvent(caSystemStarted, "CA_CHANGE"); return caSystemStarted; } // method restartCaSystem @Override public boolean notifyCaChange() throws CaMgmtException { try { SystemEvent systemEvent = new SystemEvent(EVENT_CACHAGNE, lockInstanceId, System.currentTimeMillis() / 1000L); queryExecutor.changeSystemEvent(systemEvent); LOG.info("notified the change of CA system"); return true; } catch (CaMgmtException ex) { LogUtil.warn(LOG, ex, "could not notify slave CAs to restart"); return false; } } // method notifyCaChange public void startCaSystem() { boolean caSystemStarted = false; try { caSystemStarted = doStartCaSystem(); } catch (Throwable th) { LogUtil.error(LOG, th, "could not start CA system"); } if (!caSystemStarted) { String msg = "could not start CA system"; LOG.error(msg); } auditLogPciEvent(caSystemStarted, "START"); } // method startCaSystem private boolean doStartCaSystem() { if (caSystemSetuped) { return true; } initializing = true; shutdownScheduledThreadPoolExecutor(); try { LOG.info("starting CA system"); try { init(); } catch (Exception ex) { LogUtil.error(LOG, ex); return false; } this.lastStartTime = new Date(); x509cas.clear(); x509Responders.clear(); scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(10); scheduledThreadPoolExecutor.setRemoveOnCancelPolicy(true); List<String> startedCaNames = new LinkedList<>(); List<String> failedCaNames = new LinkedList<>(); // Add the CAs to the store for (String caName : caInfos.keySet()) { CaStatus status = caInfos.get(caName).getCaEntry().getStatus(); if (CaStatus.ACTIVE != status) { continue; } if (startCa(caName)) { startedCaNames.add(caName); LOG.info("started CA {}", caName); } else { failedCaNames.add(caName); LOG.error("could not start CA {}", caName); } } caSystemSetuped = true; StringBuilder sb = new StringBuilder(); sb.append("started CA system"); Set<String> caAliasNames = getCaAliasNames(); Set<String> names = new HashSet<>(getCaNames()); if (names.size() > 0) { sb.append(" with following CAs: "); for (String aliasName : caAliasNames) { String name = getCaNameForAlias(aliasName); names.remove(name); sb.append(name).append(" (alias ").append(aliasName).append(")").append(", "); } for (String name : names) { sb.append(name).append(", "); } int len = sb.length(); sb.delete(len - 2, len); scheduledThreadPoolExecutor.scheduleAtFixedRate( new CertsInQueuePublisher(), 120, 120, TimeUnit.SECONDS); scheduledThreadPoolExecutor.scheduleAtFixedRate( new UnreferencedRequstCleaner(), 60, 24 * 60 * 60, // 1 DAY TimeUnit.SECONDS); } else { sb.append(": no CA is configured"); } if (!failedCaNames.isEmpty()) { sb.append(", and following CAs could not be started: "); for (String aliasName : caAliasNames) { String name = getCaNameForAlias(aliasName); if (failedCaNames.remove(name)) { sb.append(name).append(" (alias ").append(aliasName).append(")"); sb.append(", "); } } for (String name : failedCaNames) { sb.append(name).append(", "); } int len = sb.length(); sb.delete(len - 2, len); } LOG.info("{}", sb); } finally { initializing = false; if (!masterMode && persistentScheduledThreadPoolExecutor == null) { persistentScheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(1); persistentScheduledThreadPoolExecutor.setRemoveOnCancelPolicy(true); persistentScheduledThreadPoolExecutor.scheduleAtFixedRate(new CaRestarter(), 300, 300, TimeUnit.SECONDS); } } return true; } // method doStartCaSystem private boolean startCa(final String caName) { X509CaInfo caEntry = caInfos.get(caName); String extraControl = caEntry.getCaEntry().getExtraControl(); if (StringUtil.isNotBlank(extraControl)) { ConfPairs cp = new ConfPairs(extraControl); String str = cp.getValue(RevokeSuspendedCertsControl.KEY_REVOCATION_ENABLED); boolean enabled = false; if (str != null) { enabled = Boolean.parseBoolean(str); } if (enabled) { str = cp.getValue(RevokeSuspendedCertsControl.KEY_REVOCATION_REASON); CrlReason reason = (str == null) ? CrlReason.CESSATION_OF_OPERATION : CrlReason.forNameOrText(str); str = cp.getValue(RevokeSuspendedCertsControl.KEY_UNCHANGED_SINCE); CertValidity unchangedSince = (str == null) ? new CertValidity(15, Unit.DAY) : CertValidity.getInstance(str); RevokeSuspendedCertsControl control = new RevokeSuspendedCertsControl(reason, unchangedSince); caEntry.setRevokeSuspendedCertsControl(control); } } boolean signerRequired = caEntry.isSignerRequired(); X509CrlSignerEntryWrapper crlSignerEntry = null; String crlSignerName = caEntry.getCrlSignerName(); // CRL will be generated only in master mode if (signerRequired && masterMode && crlSignerName != null) { crlSignerEntry = crlSigners.get(crlSignerName); try { crlSignerEntry.getDbEntry().setConfFaulty(true); crlSignerEntry.initSigner(securityFactory); crlSignerEntry.getDbEntry().setConfFaulty(false); } catch (XiSecurityException | OperationException | InvalidConfException ex) { LogUtil.error(LOG, ex, "X09CrlSignerEntryWrapper.initSigner (name=" + crlSignerName + ")"); return false; } } X509Ca ca; try { ca = new X509Ca(this, caEntry, certstore); ca.setAuditServiceRegister(auditServiceRegister); } catch (OperationException ex) { LogUtil.error(LOG, ex, "X509CA.<init> (ca=" + caName + ")"); return false; } x509cas.put(caName, ca); X509CaCmpResponder caResponder = new X509CaCmpResponder(this, caName); x509Responders.put(caName, caResponder); return true; } // method startCa public void shutdown() { LOG.info("stopping CA system"); shutdownScheduledThreadPoolExecutor(); if (persistentScheduledThreadPoolExecutor != null) { persistentScheduledThreadPoolExecutor.shutdown(); while (!persistentScheduledThreadPoolExecutor.isTerminated()) { try { Thread.sleep(100); } catch (InterruptedException ex) { LOG.error("interrupted: {}", ex.getMessage()); } } persistentScheduledThreadPoolExecutor = null; } for (String caName : x509cas.keySet()) { X509Ca ca = x509cas.get(caName); try { ca.shutdown(); } catch (Throwable th) { LOG.info("could not call ca.shutdown() for CA '{}': {}", caName, th.getMessage()); } } if (caLockedByMe) { unlockCa(); } File caLockFile = new File("calock"); if (caLockFile.exists()) { caLockFile.delete(); } for (String dsName :datasources.keySet()) { DataSourceWrapper ds = datasources.get(dsName); try { ds.shutdown(); } catch (Exception ex) { LogUtil.warn(LOG, ex, "could not shutdown datasource " + dsName); } } auditLogPciEvent(true, "SHUTDOWN"); LOG.info("stopped CA system"); } // method shutdown @Override public X509CaCmpResponder getX509CaResponder(final String name) { ParamUtil.requireNonBlank("name", name); return x509Responders.get(name.toUpperCase()); } public ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor() { return scheduledThreadPoolExecutor; } @Override public Set<String> getCertprofileNames() { return certprofileDbEntries.keySet(); } @Override public Set<String> getPublisherNames() { return publisherDbEntries.keySet(); } @Override public Set<String> getRequestorNames() { return requestorDbEntries.keySet(); } @Override public Set<String> getResponderNames() { return responderDbEntries.keySet(); } @Override public Set<String> getCrlSignerNames() { return crlSigners.keySet(); } @Override public Set<String> getCmpControlNames() { return cmpControlDbEntries.keySet(); } @Override public Set<String> getCaNames() { return caInfos.keySet(); } @Override public Set<String> getSuccessfulCaNames() { Set<String> ret = new HashSet<>(); for (String name : x509cas.keySet()) { if (CaStatus.ACTIVE == caInfos.get(name).getStatus()) { ret.add(name); } } return ret; } @Override public Set<String> getFailedCaNames() { Set<String> ret = new HashSet<>(); for (String name : caInfos.keySet()) { if (CaStatus.ACTIVE == caInfos.get(name).getStatus() && !x509cas.containsKey(name)) { ret.add(name); } } return ret; } @Override public Set<String> getInactiveCaNames() { Set<String> ret = new HashSet<>(); for (String name : caInfos.keySet()) { if (CaStatus.INACTIVE == caInfos.get(name).getStatus()) { ret.add(name); } } return ret; } private void initRequestors() throws CaMgmtException { if (requestorsInitialized) { return; } idNameMap.clearRequestor(); requestorDbEntries.clear(); requestors.clear(); List<String> names = queryExecutor.getNamesFromTable("REQUESTOR"); for (String name : names) { if (RequestorInfo.NAME_BY_CA.equals(name)) { Integer id = queryExecutor.getRequestorId(name); NameId ident = new NameId(id, name); byCaRequestor = new ByCaRequestorInfo(ident); idNameMap.addRequestor(ident); } else if (RequestorInfo.NAME_BY_USER.equals(name)) { Integer id = queryExecutor.getRequestorId(name); byUserRequestorId = new NameId(id, name); idNameMap.addRequestor(byUserRequestorId); } else { CmpRequestorEntry requestorDbEntry = queryExecutor.createRequestor(name); if (requestorDbEntry == null) { continue; } idNameMap.addRequestor(requestorDbEntry.getIdent()); requestorDbEntries.put(name, requestorDbEntry); CmpRequestorEntryWrapper requestor = new CmpRequestorEntryWrapper(); requestor.setDbEntry(requestorDbEntry); requestors.put(name, requestor); } } requestorsInitialized = true; } // method initRequestors private void initResponders() throws CaMgmtException { if (responderInitialized) { return; } responderDbEntries.clear(); responders.clear(); List<String> names = queryExecutor.getNamesFromTable("RESPONDER"); for (String name : names) { CmpResponderEntry dbEntry = queryExecutor.createResponder(name); if (dbEntry == null) { LOG.error("could not initialize Responder '{}'", name); continue; } dbEntry.setConfFaulty(true); responderDbEntries.put(name, dbEntry); CmpResponderEntryWrapper responder = createCmpResponder(dbEntry); if (responder != null) { dbEntry.setConfFaulty(false); responders.put(name, responder); } } responderInitialized = true; } // method initResponders private void initEnvironmentParamters() throws CaMgmtException { if (environmentParametersInitialized) { return; } Map<String, String> map = queryExecutor.createEnvParameters(); envParameterResolver.clear(); for (String name : map.keySet()) { envParameterResolver.addEnvParam(name, map.get(name)); } environmentParametersInitialized = true; } // method initEnvironmentParamters private void initCaAliases() throws CaMgmtException { if (caAliasesInitialized) { return; } Map<String, Integer> map = queryExecutor.createCaAliases(); caAliases.clear(); for (String aliasName : map.keySet()) { caAliases.put(aliasName, map.get(aliasName)); } caAliasesInitialized = true; } // method initCaAliases private void initCertprofiles() throws CaMgmtException { if (certprofilesInitialized) { return; } for (String name : certprofiles.keySet()) { shutdownCertprofile(certprofiles.get(name)); } certprofileDbEntries.clear(); idNameMap.clearCertprofile(); certprofiles.clear(); List<String> names = queryExecutor.getNamesFromTable("PROFILE"); for (String name : names) { CertprofileEntry dbEntry = queryExecutor.createCertprofile(name); if (dbEntry == null) { LOG.error("could not initialize Certprofile '{}'", name); continue; } idNameMap.addCertprofile(dbEntry.getIdent()); dbEntry.setFaulty(true); certprofileDbEntries.put(name, dbEntry); IdentifiedX509Certprofile profile = createCertprofile(dbEntry); if (profile != null) { dbEntry.setFaulty(false); certprofiles.put(name, profile); } } certprofilesInitialized = true; } // method initCertprofiles private void initPublishers() throws CaMgmtException { if (publishersInitialized) { return; } for (String name : publishers.keySet()) { shutdownPublisher(publishers.get(name)); } publishers.clear(); publisherDbEntries.clear(); idNameMap.clearPublisher(); List<String> names = queryExecutor.getNamesFromTable("PUBLISHER"); for (String name : names) { PublisherEntry dbEntry = queryExecutor.createPublisher(name); if (dbEntry == null) { LOG.error("could not initialize publisher '{}'", name); continue; } idNameMap.addPublisher(dbEntry.getIdent()); dbEntry.setFaulty(true); publisherDbEntries.put(name, dbEntry); IdentifiedX509CertPublisher publisher = createPublisher(dbEntry); if (publisher != null) { dbEntry.setFaulty(false); publishers.put(name, publisher); } } publishersInitialized = true; } // method initPublishers private void initCrlSigners() throws CaMgmtException { if (crlSignersInitialized) { return; } crlSigners.clear(); crlSignerDbEntries.clear(); List<String> names = queryExecutor.getNamesFromTable("CRLSIGNER"); for (String name : names) { X509CrlSignerEntry dbEntry = queryExecutor.createCrlSigner(name); if (dbEntry == null) { LOG.error("could not initialize CRL signer '{}'", name); continue; } crlSignerDbEntries.put(name, dbEntry); X509CrlSignerEntryWrapper crlSigner = createX509CrlSigner(dbEntry); crlSigners.put(name, crlSigner); } crlSignersInitialized = true; } // method initCrlSigners private void initCmpControls() throws CaMgmtException { if (cmpControlInitialized) { return; } cmpControls.clear(); cmpControlDbEntries.clear(); List<String> names = queryExecutor.getNamesFromTable("CMPCONTROL"); for (String name : names) { CmpControlEntry cmpControlDb = queryExecutor.createCmpControl(name); if (cmpControlDb == null) { continue; } cmpControlDb.setFaulty(true); cmpControlDbEntries.put(name, cmpControlDb); CmpControl cmpControl; try { cmpControl = new CmpControl(cmpControlDb); cmpControlDb.setFaulty(false); cmpControls.put(name, cmpControl); } catch (InvalidConfException ex) { LogUtil.error(LOG, ex, "could not initialize CMP control " + name + ", ignore it"); } } cmpControlInitialized = true; } // method initCmpControls private void initSceps() throws CaMgmtException { if (scepsInitialized) { return; } sceps.clear(); scepDbEntries.clear(); List<String> names = queryExecutor.getNamesFromTable("SCEP"); for (String name : names) { ScepEntry scepDb = queryExecutor.getScep(name, idNameMap); if (scepDb == null) { continue; } scepDb.setConfFaulty(true); scepDbEntries.put(name, scepDb); try { Scep scep = new Scep(scepDb, this); scepDb.setConfFaulty(false); sceps.put(name, scep); } catch (CaMgmtException ex) { LogUtil.error(LOG, ex, "could not initialize SCEP entry " + name + ", ignore it"); } } scepsInitialized = true; } // method initSceps private void initCas() throws CaMgmtException { if (casInitialized) { return; } caInfos.clear(); caHasRequestors.clear(); caHasPublishers.clear(); caHasProfiles.clear(); idNameMap.clearCa(); List<String> names = queryExecutor.getNamesFromTable("CA"); for (String name : names) { createCa(name); } casInitialized = true; } // method initCas private boolean createCa(final String name) throws CaMgmtException { caInfos.remove(name); idNameMap.removeCa(name); caHasProfiles.remove(name); caHasPublishers.remove(name); caHasRequestors.remove(name); X509Ca oldCa = x509cas.remove(name); x509Responders.remove(name); if (oldCa != null) { oldCa.shutdown(); } X509CaInfo ca = queryExecutor.createCaInfo(name, masterMode, certstore); caInfos.put(name, ca); idNameMap.addCa(ca.getIdent()); Set<CaHasRequestorEntry> caHasRequestorList = queryExecutor.createCaHasRequestors(ca.getIdent()); caHasRequestors.put(name, caHasRequestorList); Set<Integer> profileIds = queryExecutor.createCaHasProfiles(ca.getIdent()); Set<String> profileNames = new HashSet<>(); for (Integer id : profileIds) { profileNames.add(idNameMap.getCertprofileName(id)); } caHasProfiles.put(name, profileNames); Set<Integer> publisherIds = queryExecutor.createCaHasPublishers(ca.getIdent()); Set<String> publisherNames = new HashSet<>(); for (Integer id : publisherIds) { publisherNames.add(idNameMap.getPublisherName(id)); } caHasPublishers.put(name, publisherNames); return true; } // method createCa public void commitNextCrlNo(final NameId ca, final long nextCrlNo) throws OperationException { try { queryExecutor.commitNextCrlNoIfLess(ca, nextCrlNo); } catch (CaMgmtException ex) { if (ex.getCause() instanceof DataAccessException) { throw new OperationException(ErrorCode.DATABASE_FAILURE, ex.getMessage()); } else { throw new OperationException(ErrorCode.SYSTEM_FAILURE, ex.getMessage()); } } catch (RuntimeException ex) { throw new OperationException(ErrorCode.SYSTEM_FAILURE, ex.getMessage()); } } public ByUserRequestorInfo createByUserRequestor(CaHasUserEntry caHasUser) { return new ByUserRequestorInfo(byUserRequestorId, caHasUser); } @Override public boolean addCa(final CaEntry caEntry) throws CaMgmtException { ParamUtil.requireNonNull("caEntry", caEntry); asssertMasterMode(); NameId ident = caEntry.getIdent(); String name = ident.getName(); if (caInfos.containsKey(name)) { throw new CaMgmtException("CA named " + name + " exists"); } if (caEntry instanceof X509CaEntry) { try { X509CaEntry tmpCaEntry = (X509CaEntry) caEntry; List<String[]> signerConfs = CaEntry.splitCaSignerConfs(tmpCaEntry.getSignerConf()); ConcurrentContentSigner signer; for (String[] m : signerConfs) { SignerConf signerConf = new SignerConf(m[1]); signer = securityFactory.createSigner(tmpCaEntry.getSignerType(), signerConf, tmpCaEntry.getCertificate()); if (tmpCaEntry.getCertificate() == null) { if (signer.getCertificate() == null) { throw new CaMgmtException( "CA signer without certificate is not allowed"); } tmpCaEntry.setCertificate(signer.getCertificate()); } } } catch (XiSecurityException | ObjectCreationException ex) { throw new CaMgmtException( "could not create signer for new CA " + name + ": " + ex.getMessage(), ex); } } queryExecutor.addCa(caEntry); if (!createCa(name)) { LOG.error("could not create CA {}", name); } else { if (startCa(name)) { LOG.info("started CA {}", name); } else { LOG.error("could not start CA {}", name); } } return true; } // method addCa @Override public X509CaEntry getCa(final String name) { ParamUtil.requireNonBlank("name", name); X509CaInfo caInfo = caInfos.get(name.toUpperCase()); return (caInfo == null) ? null : caInfo.getCaEntry(); } @Override public boolean changeCa(final ChangeCaEntry entry) throws CaMgmtException { ParamUtil.requireNonNull("entry", entry); asssertMasterMode(); String name = entry.getIdent().getName(); NameId ident = idNameMap.getCa(name); if (ident == null) { throw new CaMgmtException("No CA named " + name + " does not exist"); } entry.getIdent().setId(ident.getId()); boolean changed = queryExecutor.changeCa(entry, securityFactory); if (!changed) { LOG.info("no change of CA '{}' is processed", name); } else { if (!createCa(name)) { LOG.error("could not create CA {}", name); } else { X509CaInfo caInfo = caInfos.get(name); if (CaStatus.ACTIVE != caInfo.getCaEntry().getStatus()) { return changed; } if (startCa(name)) { LOG.info("started CA {}", name); } else { LOG.error("could not start CA {}", name); } } } return changed; } // method changeCa @Override public boolean removeCertprofileFromCa(String profileName, String caName) throws CaMgmtException { ParamUtil.requireNonBlank("profileName", profileName); ParamUtil.requireNonBlank("caName", caName); asssertMasterMode(); profileName = profileName.toUpperCase(); caName = caName.toUpperCase(); boolean bo = queryExecutor.removeCertprofileFromCa(profileName, caName); if (!bo) { return false; } if (caHasProfiles.containsKey(caName)) { Set<String> set = caHasProfiles.get(caName); if (set != null) { set.remove(profileName); } } return true; } // method removeCertprofileFromCa @Override public boolean addCertprofileToCa(String profileName, String caName) throws CaMgmtException { ParamUtil.requireNonBlank("profileName", profileName); ParamUtil.requireNonBlank("caName", caName); asssertMasterMode(); profileName = profileName.toUpperCase(); caName = caName.toUpperCase(); NameId ident = idNameMap.getCertprofile(profileName); if (ident == null) { LOG.warn("CertProfile {} does not exist", profileName); return false; } Set<String> set = caHasProfiles.get(caName); if (set == null) { set = new HashSet<>(); caHasProfiles.put(caName, set); } else { if (set.contains(profileName)) { LOG.warn("CertProfile {} already associated with CA {}", profileName, caName); return false; } } if (!certprofiles.containsKey(profileName)) { throw new CaMgmtException("certprofile '" + profileName + "' is faulty"); } queryExecutor.addCertprofileToCa(ident, idNameMap.getCa(caName)); set.add(profileName); return true; } // method addCertprofileToCa @Override public boolean removePublisherFromCa(String publisherName, String caName) throws CaMgmtException { ParamUtil.requireNonBlank("publisherName", publisherName); ParamUtil.requireNonBlank("caName", caName); asssertMasterMode(); publisherName = publisherName.toUpperCase(); caName = caName.toUpperCase(); if (!queryExecutor.removePublisherFromCa(publisherName, caName)) { return false; } Set<String> publisherNames = caHasPublishers.get(caName); if (publisherNames != null) { publisherNames.remove(publisherName); } return true; } // method removePublisherFromCa @Override public boolean addPublisherToCa(String publisherName, String caName) throws CaMgmtException { ParamUtil.requireNonBlank("publisherName", publisherName); ParamUtil.requireNonBlank("caName", caName); asssertMasterMode(); publisherName = publisherName.toUpperCase(); caName = caName.toUpperCase(); NameId ident = idNameMap.getPublisher(publisherName); if (ident == null) { LOG.warn("Publisher {} does not exist", publisherName); return false; } Set<String> publisherNames = caHasPublishers.get(caName); if (publisherNames == null) { publisherNames = new HashSet<>(); caHasPublishers.put(caName, publisherNames); } else { if (publisherNames.contains(publisherName)) { LOG.warn("CertProfile {} already associated with CA {}", publisherName, caName); return false; } } IdentifiedX509CertPublisher publisher = publishers.get(publisherName); if (publisher == null) { throw new CaMgmtException("publisher '" + publisherName + "' is faulty"); } queryExecutor.addPublisherToCa(idNameMap.getPublisher(publisherName), idNameMap.getCa(caName)); publisherNames.add(publisherName); caHasPublishers.get(caName).add(publisherName); publisher.caAdded(caInfos.get(caName).getCertificate()); return true; } // method addPublisherToCa @Override public Set<String> getCertprofilesForCa(final String caName) { ParamUtil.requireNonBlank("caName", caName); return caHasProfiles.get(caName.toUpperCase()); } @Override public Set<CaHasRequestorEntry> getRequestorsForCa(final String caName) { ParamUtil.requireNonBlank("caName", caName); return caHasRequestors.get(caName.toUpperCase()); } @Override public CmpRequestorEntry getRequestor(final String name) { ParamUtil.requireNonBlank("name", name); return requestorDbEntries.get(name.toUpperCase()); } public CmpRequestorEntryWrapper getCmpRequestorWrapper(final String name) { ParamUtil.requireNonBlank("name", name); return requestors.get(name.toUpperCase()); } @Override public boolean addRequestor(final CmpRequestorEntry dbEntry) throws CaMgmtException { ParamUtil.requireNonNull("dbEntry", dbEntry); asssertMasterMode(); String name = dbEntry.getIdent().getName(); if (requestorDbEntries.containsKey(name)) { return false; } CmpRequestorEntryWrapper requestor = new CmpRequestorEntryWrapper(); requestor.setDbEntry(dbEntry); queryExecutor.addRequestor(dbEntry); idNameMap.addRequestor(dbEntry.getIdent()); requestorDbEntries.put(name, dbEntry); requestors.put(name, requestor); return true; } // method addRequestor @Override public boolean removeRequestor(String requestorName) throws CaMgmtException { ParamUtil.requireNonBlank("requestorName", requestorName); asssertMasterMode(); requestorName = requestorName.toUpperCase(); for (String caName : caHasRequestors.keySet()) { removeRequestorFromCa(requestorName, caName); } boolean bo = queryExecutor.deleteRowWithName(requestorName, "REQUESTOR"); if (!bo) { return false; } idNameMap.removeRequestor(requestorDbEntries.get(requestorName).getIdent().getId()); requestorDbEntries.remove(requestorName); requestors.remove(requestorName); LOG.info("removed requestor '{}'", requestorName); return true; } // method removeRequestor @Override public boolean changeRequestor(String name, final String base64Cert) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); asssertMasterMode(); name = name.toUpperCase(); if (base64Cert == null) { return false; } NameId ident = idNameMap.getRequestor(name); if (ident == null) { throw new CaMgmtException("Requestor named " + name + " does not exists"); } CmpRequestorEntryWrapper requestor = queryExecutor.changeRequestor(ident, base64Cert); if (requestor == null) { return false; } requestorDbEntries.remove(name); requestors.remove(name); requestorDbEntries.put(name, requestor.getDbEntry()); requestors.put(name, requestor); return true; } // method changeRequestor @Override public boolean removeRequestorFromCa(String requestorName, String caName) throws CaMgmtException { ParamUtil.requireNonBlank("requestorName", requestorName); ParamUtil.requireNonBlank("caName", caName); asssertMasterMode(); requestorName = requestorName.toUpperCase(); caName = caName.toUpperCase(); if (requestorName.equals(RequestorInfo.NAME_BY_CA) || requestorName.equals(RequestorInfo.NAME_BY_USER)) { throw new CaMgmtException("removing requestor " + requestorName + " is not permitted"); } boolean bo = queryExecutor.removeRequestorFromCa(requestorName, caName); if (bo && caHasRequestors.containsKey(caName)) { Set<CaHasRequestorEntry> entries = caHasRequestors.get(caName); CaHasRequestorEntry entry = null; for (CaHasRequestorEntry m : entries) { if (m.getRequestorIdent().getName().equals(requestorName)) { entry = m; } } entries.remove(entry); } return bo; } // method removeRequestorFromCa @Override public boolean addRequestorToCa(final CaHasRequestorEntry requestor, String caName) throws CaMgmtException { ParamUtil.requireNonNull("requestor", requestor); ParamUtil.requireNonBlank("caName", caName); asssertMasterMode(); caName = caName.toUpperCase(); NameId requestorIdent = requestor.getRequestorIdent(); NameId ident = idNameMap.getRequestor(requestorIdent.getName()); if (ident == null) { LOG.warn("Requestor {} does not exist", requestorIdent.getName()); return false; } // Set the ID of requestor requestorIdent.setId(ident.getId()); Set<CaHasRequestorEntry> cmpRequestors = caHasRequestors.get(caName); if (cmpRequestors == null) { cmpRequestors = new HashSet<>(); caHasRequestors.put(caName, cmpRequestors); } else { for (CaHasRequestorEntry entry : cmpRequestors) { if (entry.getRequestorIdent().getName().equals(requestorIdent.getName())) { LOG.warn("Requestor {} already associated with CA {}", requestorIdent.getName(), caName); // already added return false; } } } cmpRequestors.add(requestor); queryExecutor.addRequestorToCa(requestor, idNameMap.getCa(caName)); caHasRequestors.get(caName).add(requestor); return true; } // method addRequestorToCa @Override public boolean removeUserFromCa(final String userName, final String caName) throws CaMgmtException { ParamUtil.requireNonBlank("userName", userName); ParamUtil.requireNonBlank("caName", caName); asssertMasterMode(); return queryExecutor.removeUserFromCa(userName.toUpperCase(), caName.toUpperCase()); } @Override public boolean addUserToCa(final CaHasUserEntry user, final String caName) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); asssertMasterMode(); X509Ca ca = getX509Ca(caName.toUpperCase()); return queryExecutor.addUserToCa(user, ca.getCaIdent()); } @Override public Map<String, CaHasUserEntry> getCaHasUsers(String user) throws CaMgmtException { ParamUtil.requireNonBlank("user", user); return queryExecutor.getCaHasUsers(user, idNameMap); } @Override public CertprofileEntry getCertprofile(final String profileName) { ParamUtil.requireNonBlank("profileName", profileName); return certprofileDbEntries.get(profileName.toUpperCase()); } @Override public boolean removeCertprofile(String profileName) throws CaMgmtException { ParamUtil.requireNonBlank("profileName", profileName); asssertMasterMode(); profileName = profileName.toUpperCase(); for (String caName : caHasProfiles.keySet()) { removeCertprofileFromCa(profileName, caName); } boolean bo = queryExecutor.deleteRowWithName(profileName, "PROFILE"); if (!bo) { return false; } LOG.info("removed profile '{}'", profileName); idNameMap.removeCertprofile(certprofileDbEntries.get(profileName).getIdent().getId()); certprofileDbEntries.remove(profileName); IdentifiedX509Certprofile profile = certprofiles.remove(profileName); shutdownCertprofile(profile); return true; } // method removeCertprofile @Override public boolean changeCertprofile(String name, final String type, final String conf) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); if (type == null && conf == null) { return false; } NameId ident = idNameMap.getCertprofile(name); if (ident == null) { throw new CaMgmtException("Certprofile " + name + " does not exist"); } asssertMasterMode(); name = name.toUpperCase(); IdentifiedX509Certprofile profile = queryExecutor.changeCertprofile( ident, type, conf, this); if (profile == null) { return false; } certprofileDbEntries.remove(name); IdentifiedX509Certprofile oldProfile = certprofiles.remove(name); certprofileDbEntries.put(name, profile.getDbEntry()); certprofiles.put(name, profile); if (oldProfile != null) { shutdownCertprofile(oldProfile); } return true; } // method changeCertprofile @Override public boolean addCertprofile(final CertprofileEntry dbEntry) throws CaMgmtException { ParamUtil.requireNonNull("dbEntry", dbEntry); asssertMasterMode(); String name = dbEntry.getIdent().getName(); if (certprofileDbEntries.containsKey(name)) { return false; } dbEntry.setFaulty(true); IdentifiedX509Certprofile profile = createCertprofile(dbEntry); if (profile == null) { return false; } dbEntry.setFaulty(false); certprofiles.put(name, profile); queryExecutor.addCertprofile(dbEntry); idNameMap.addCertprofile(dbEntry.getIdent()); certprofileDbEntries.put(name, dbEntry); return true; } // method addCertprofile @Override public boolean addResponder(final CmpResponderEntry dbEntry) throws CaMgmtException { ParamUtil.requireNonNull("dbEntry", dbEntry); asssertMasterMode(); String name = dbEntry.getName(); if (crlSigners.containsKey(name)) { return false; } CmpResponderEntryWrapper responder = createCmpResponder(dbEntry); queryExecutor.addResponder(dbEntry); responders.put(name, responder); responderDbEntries.put(name, dbEntry); return true; } // method addResponder @Override public boolean removeResponder(String name) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); asssertMasterMode(); name = name.toUpperCase(); boolean bo = queryExecutor.deleteRowWithName(name, "RESPONDER"); if (!bo) { return false; } for (String caName : caInfos.keySet()) { X509CaInfo caInfo = caInfos.get(caName); if (name.equals(caInfo.getResponderName())) { caInfo.setResponderName(null); } } responderDbEntries.remove(name); responders.remove(name); LOG.info("removed Responder '{}'", name); return true; } // method removeResponder @Override public boolean changeResponder(String name, final String type, final String conf, final String base64Cert) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); asssertMasterMode(); name = name.toUpperCase(); if (type == null && conf == null && base64Cert == null) { return false; } CmpResponderEntryWrapper newResponder = queryExecutor.changeResponder(name, type, conf, base64Cert, this); if (newResponder == null) { return false; } responders.remove(name); responderDbEntries.remove(name); responderDbEntries.put(name, newResponder.getDbEntry()); responders.put(name, newResponder); return true; } // method changeResponder @Override public CmpResponderEntry getResponder(final String name) { ParamUtil.requireNonBlank("name", name); return responderDbEntries.get(name.toUpperCase()); } public CmpResponderEntryWrapper getCmpResponderWrapper(final String name) { ParamUtil.requireNonBlank("name", name); return responders.get(name.toUpperCase()); } @Override public boolean addCrlSigner(final X509CrlSignerEntry dbEntry) throws CaMgmtException { ParamUtil.requireNonNull("dbEntry", dbEntry); asssertMasterMode(); String name = dbEntry.getName(); if (crlSigners.containsKey(name)) { return false; } X509CrlSignerEntryWrapper crlSigner = createX509CrlSigner(dbEntry); X509CrlSignerEntry tmpDbEntry = crlSigner.getDbEntry(); queryExecutor.addCrlSigner(tmpDbEntry); crlSigners.put(name, crlSigner); crlSignerDbEntries.put(name, tmpDbEntry); return true; } // method addCrlSigner @Override public boolean removeCrlSigner(String name) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); asssertMasterMode(); name = name.toUpperCase(); boolean bo = queryExecutor.deleteRowWithName(name, "CRLSIGNER"); if (!bo) { return false; } for (String caName : caInfos.keySet()) { X509CaInfo caInfo = caInfos.get(caName); if (name.equals(caInfo.getCrlSignerName())) { caInfo.setCrlSignerName(null); } } crlSigners.remove(name); crlSignerDbEntries.remove(name); LOG.info("removed CRL signer '{}'", name); return true; } // method removeCrlSigner @Override public boolean changeCrlSigner(final X509ChangeCrlSignerEntry dbEntry) throws CaMgmtException { ParamUtil.requireNonNull("dbEntry", dbEntry); asssertMasterMode(); String name = dbEntry.getName(); String signerType = dbEntry.getSignerType(); String signerConf = dbEntry.getSignerConf(); String signerCert = dbEntry.getBase64Cert(); String crlControl = dbEntry.getCrlControl(); X509CrlSignerEntryWrapper crlSigner = queryExecutor.changeCrlSigner(name, signerType, signerConf, signerCert, crlControl, this); if (crlSigner == null) { return false; } crlSigners.remove(name); crlSignerDbEntries.remove(name); crlSignerDbEntries.put(name, crlSigner.getDbEntry()); crlSigners.put(name, crlSigner); return true; } // method changeCrlSigner @Override public X509CrlSignerEntry getCrlSigner(final String name) { ParamUtil.requireNonBlank("name", name); return crlSignerDbEntries.get(name.toUpperCase()); } public X509CrlSignerEntryWrapper getCrlSignerWrapper(final String name) { ParamUtil.requireNonBlank("name", name); return crlSigners.get(name.toUpperCase()); } @Override public boolean addPublisher(final PublisherEntry dbEntry) throws CaMgmtException { ParamUtil.requireNonNull("dbEntry", dbEntry); asssertMasterMode(); String name = dbEntry.getIdent().getName(); if (publisherDbEntries.containsKey(name)) { return false; } dbEntry.setFaulty(true); IdentifiedX509CertPublisher publisher = createPublisher(dbEntry); if (publisher == null) { return false; } dbEntry.setFaulty(false); queryExecutor.addPublisher(dbEntry); idNameMap.addPublisher(dbEntry.getIdent()); publisherDbEntries.put(name, dbEntry); publishers.put(name, publisher); return true; } // method addPublisher @Override public List<PublisherEntry> getPublishersForCa(String caName) { ParamUtil.requireNonBlank("caName", caName); caName = caName.toUpperCase(); Set<String> publisherNames = caHasPublishers.get(caName); if (publisherNames == null) { return Collections.emptyList(); } List<PublisherEntry> ret = new ArrayList<>(publisherNames.size()); for (String publisherName : publisherNames) { ret.add(publisherDbEntries.get(publisherName)); } return ret; } // method getPublishersForCa @Override public PublisherEntry getPublisher(final String name) { ParamUtil.requireNonBlank("name", name); return publisherDbEntries.get(name.toUpperCase()); } @Override public boolean removePublisher(String name) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); asssertMasterMode(); name = name.toUpperCase(); for (String caName : caHasPublishers.keySet()) { removePublisherFromCa(name, caName); } boolean bo = queryExecutor.deleteRowWithName(name, "PUBLISHER"); if (!bo) { return false; } LOG.info("removed publisher '{}'", name); publisherDbEntries.remove(name); IdentifiedX509CertPublisher publisher = publishers.remove(name); shutdownPublisher(publisher); return true; } // method removePublisher @Override public boolean changePublisher(String name, final String type, final String conf) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); asssertMasterMode(); name = name.toUpperCase(); if (type == null && conf == null) { return false; } IdentifiedX509CertPublisher publisher = queryExecutor.changePublisher(name, type, conf, this); if (publisher == null) { return false; } IdentifiedX509CertPublisher oldPublisher = publishers.remove(name); shutdownPublisher(oldPublisher); publisherDbEntries.put(name, publisher.getDbEntry()); publishers.put(name, publisher); return true; } // method changePublisher @Override public CmpControlEntry getCmpControl(final String name) { ParamUtil.requireNonBlank("name", name); return cmpControlDbEntries.get(name.toUpperCase()); } public CmpControl getCmpControlObject(final String name) { ParamUtil.requireNonBlank("name", name); return cmpControls.get(name.toUpperCase()); } @Override public boolean addCmpControl(final CmpControlEntry dbEntry) throws CaMgmtException { ParamUtil.requireNonNull("dbEntry", dbEntry); asssertMasterMode(); final String name = dbEntry.getName(); if (cmpControlDbEntries.containsKey(name)) { return false; } CmpControl cmpControl; try { cmpControl = new CmpControl(dbEntry); } catch (InvalidConfException ex) { LogUtil.error(LOG, ex, "could not add CMP control to certStore"); return false; } CmpControlEntry tmpDbEntry = cmpControl.getDbEntry(); queryExecutor.addCmpControl(tmpDbEntry); cmpControls.put(name, cmpControl); cmpControlDbEntries.put(name, tmpDbEntry); return true; } // method addCmpControl @Override public boolean removeCmpControl(String name) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); asssertMasterMode(); name = name.toUpperCase(); boolean bo = queryExecutor.deleteRowWithName(name, "CMPCONTROL"); if (!bo) { return false; } for (String caName : caInfos.keySet()) { X509CaInfo caInfo = caInfos.get(caName); if (name.equals(caInfo.getCmpControlName())) { caInfo.setCmpControlName(null); } } cmpControlDbEntries.remove(name); cmpControls.remove(name); LOG.info("removed CMPControl '{}'", name); return true; } // method removeCmpControl @Override public boolean changeCmpControl(String name, final String conf) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); ParamUtil.requireNonBlank("conf", conf); asssertMasterMode(); name = name.toUpperCase(); CmpControl newCmpControl = queryExecutor.changeCmpControl(name, conf); if (newCmpControl == null) { return false; } cmpControlDbEntries.put(name, newCmpControl.getDbEntry()); cmpControls.put(name, newCmpControl); return true; } // method changeCmpControl public EnvParameterResolver getEnvParameterResolver() { return envParameterResolver; } @Override public Set<String> getEnvParamNames() { return envParameterResolver.getAllParameterNames(); } @Override public String getEnvParam(final String name) { ParamUtil.requireNonBlank("name", name); return envParameterResolver.getEnvParam(name); } @Override public boolean addEnvParam(final String name, final String value) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); ParamUtil.requireNonBlank("value", value); asssertMasterMode(); if (envParameterResolver.getEnvParam(name) != null) { return false; } queryExecutor.addEnvParam(name, value); envParameterResolver.addEnvParam(name, value); return true; } @Override public boolean removeEnvParam(final String name) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); asssertMasterMode(); boolean bo = queryExecutor.deleteRowWithName(name, "ENVIRONMENT"); if (!bo) { return false; } LOG.info("removed environment param '{}'", name); envParameterResolver.removeEnvParam(name); return true; } @Override public boolean changeEnvParam(final String name, final String value) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); ParamUtil.requireNonNull("value", value); asssertMasterMode(); assertNotNull("value", value); if (envParameterResolver.getEnvParam(name) == null) { throw new CaMgmtException("could not find environment paramter " + name); } boolean changed = queryExecutor.changeEnvParam(name, value); if (!changed) { return false; } envParameterResolver.addEnvParam(name, value); return true; } // method changeEnvParam public String getCaConfFile() { return caConfFile; } public void setCaConfFile(final String caConfFile) { this.caConfFile = caConfFile; } @Override public boolean addCaAlias(String aliasName, String caName) throws CaMgmtException { ParamUtil.requireNonBlank("aliasName", aliasName); ParamUtil.requireNonBlank("caName", caName); asssertMasterMode(); aliasName = aliasName.toUpperCase(); caName = caName.toUpperCase(); X509Ca ca = x509cas.get(caName); if (ca == null) { return false; } String tmpAlias = aliasName.toUpperCase(); if (caAliases.get(tmpAlias) != null) { return false; } queryExecutor.addCaAlias(tmpAlias, ca.getCaIdent()); caAliases.put(tmpAlias, ca.getCaIdent().getId()); return true; } // method addCaAlias @Override public boolean removeCaAlias(String name) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); asssertMasterMode(); name = name.toUpperCase(); boolean bo = queryExecutor.removeCaAlias(name); if (!bo) { return false; } caAliases.remove(name); return true; } @Override public String getCaNameForAlias(String aliasName) { ParamUtil.requireNonBlank("aliasName", aliasName); aliasName = aliasName.toUpperCase(); Integer caId = caAliases.get(aliasName); for (String name : x509cas.keySet()) { X509Ca ca = x509cas.get(name); if (ca.getCaIdent().getId() == caId) { return ca.getCaIdent().getName(); } } return null; } @Override public Set<String> getAliasesForCa(String caName) { ParamUtil.requireNonBlank("caName", caName); caName = caName.toUpperCase(); Set<String> aliases = new HashSet<>(); X509Ca ca = x509cas.get(caName); if (ca == null) { return aliases; } NameId caIdent = ca.getCaIdent(); for (String alias : caAliases.keySet()) { Integer thisCaId = caAliases.get(alias); if (thisCaId == caIdent.getId()) { aliases.add(alias); } } return aliases; } // method getAliasesForCa @Override public Set<String> getCaAliasNames() { return caAliases.keySet(); } @Override public boolean removeCa(String caName) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); asssertMasterMode(); caName = caName.toUpperCase(); boolean bo = queryExecutor.removeCa(caName); if (!bo) { return false; } LOG.info("removed CA '{}'", caName); caInfos.remove(caName); idNameMap.removeCa(caName); idNameMap.removeCa(caName); caHasProfiles.remove(caName); caHasPublishers.remove(caName); caHasRequestors.remove(caName); X509Ca ca = x509cas.remove(caName); x509Responders.remove(caName); if (ca != null) { ca.shutdown(); } return true; } // method removeCa @Override public boolean republishCertificates(String caName, final List<String> publisherNames, final int numThreads) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); ParamUtil.requireMin("numThreads", numThreads, 1); asssertMasterMode(); caName = caName.toUpperCase(); X509Ca ca = x509cas.get(caName); if (ca == null) { throw new CaMgmtException("could not find CA named " + caName); } List<String> upperPublisherNames = CollectionUtil.toUpperCaseList(publisherNames); boolean successful = ca.republishCertificates(upperPublisherNames, numThreads); if (!successful) { throw new CaMgmtException("republishing certificates of CA " + caName + " failed"); } return true; } // method republishCertificates @Override public boolean revokeCa(String caName, final CertRevocationInfo revocationInfo) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); ParamUtil.requireNonNull("revocationInfo", revocationInfo); asssertMasterMode(); caName = caName.toUpperCase(); if (!x509cas.containsKey(caName)) { return false; } LOG.info("revoking CA '{}'", caName); X509Ca ca = x509cas.get(caName); CertRevocationInfo currentRevInfo = ca.getCaInfo().getRevocationInfo(); if (currentRevInfo != null) { CrlReason currentReason = currentRevInfo.getReason(); if (currentReason != CrlReason.CERTIFICATE_HOLD) { throw new CaMgmtException("CA " + caName + " has been revoked with reason " + currentReason.name()); } } boolean bo = queryExecutor.revokeCa(caName, revocationInfo); if (!bo) { return false; } try { ca.revokeCa(revocationInfo, CaAuditConstants.MSGID_CA_mgmt); } catch (OperationException ex) { throw new CaMgmtException("could not revoke CA " + ex.getMessage(), ex); } LOG.info("revoked CA '{}'", caName); auditLogPciEvent(true, "REVOKE CA " + caName); return true; } // method revokeCa @Override public boolean unrevokeCa(String caName) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); asssertMasterMode(); caName = caName.toUpperCase(); if (!x509cas.containsKey(caName)) { throw new CaMgmtException("could not find CA named " + caName); } LOG.info("unrevoking of CA '{}'", caName); boolean bo = queryExecutor.unrevokeCa(caName); if (!bo) { return false; } X509Ca ca = x509cas.get(caName); try { ca.unrevokeCa(CaAuditConstants.MSGID_CA_mgmt); } catch (OperationException ex) { throw new CaMgmtException("could not unrevoke of CA " + ex.getMessage(), ex); } LOG.info("unrevoked CA '{}'", caName); auditLogPciEvent(true, "UNREVOKE CA " + caName); return true; } // method unrevokeCa public void setX509CertProfileFactoryRegister( final X509CertprofileFactoryRegister x509CertProfileFactoryRegister) { this.x509CertProfileFactoryRegister = x509CertProfileFactoryRegister; } public void setX509CertPublisherFactoryRegister( final X509CertPublisherFactoryRegister x509CertPublisherFactoryRegister) { this.x509CertPublisherFactoryRegister = x509CertPublisherFactoryRegister; } public void setAuditServiceRegister(final AuditServiceRegister serviceRegister) { this.auditServiceRegister = ParamUtil.requireNonNull("serviceRegister", serviceRegister); for (String name : publishers.keySet()) { IdentifiedX509CertPublisher publisherEntry = publishers.get(name); publisherEntry.setAuditServiceRegister(auditServiceRegister); } for (String name : x509cas.keySet()) { X509Ca ca = x509cas.get(name); ca.setAuditServiceRegister(serviceRegister); } } private void auditLogPciEvent(final boolean successful, final String eventType) { PciAuditEvent event = new PciAuditEvent(new Date()); event.setUserId("CA-SYSTEM"); event.setEventType(eventType); event.setAffectedResource("CORE"); if (successful) { event.setStatus(AuditStatus.SUCCESSFUL.name()); event.setLevel(AuditLevel.INFO); } else { event.setStatus(AuditStatus.FAILED.name()); event.setLevel(AuditLevel.ERROR); } auditServiceRegister.getAuditService().logEvent(event); } // method auditLogPciEvent @Override public boolean clearPublishQueue(String caName, final List<String> publisherNames) throws CaMgmtException { asssertMasterMode(); List<String> upperPublisherNames = CollectionUtil.toUpperCaseList(publisherNames); if (caName == null) { if (CollectionUtil.isNonEmpty(upperPublisherNames)) { throw new IllegalArgumentException("non-empty publisherNames is not allowed"); } try { certstore.clearPublishQueue((NameId) null, (NameId) null); return true; } catch (OperationException ex) { throw new CaMgmtException(ex.getMessage(), ex); } } caName = caName.toUpperCase(); X509Ca ca = x509cas.get(caName); if (ca == null) { throw new CaMgmtException("could not find CA named " + caName); } return ca.clearPublishQueue(upperPublisherNames); } // method clearPublishQueue private void shutdownScheduledThreadPoolExecutor() { if (scheduledThreadPoolExecutor == null) { return; } scheduledThreadPoolExecutor.shutdown(); while (!scheduledThreadPoolExecutor.isTerminated()) { try { Thread.sleep(100); } catch (InterruptedException ex) { LOG.error("interrupted: {}", ex.getMessage()); } } scheduledThreadPoolExecutor = null; } // method shutdownScheduledThreadPoolExecutor @Override public boolean revokeCertificate(String caName, final BigInteger serialNumber, final CrlReason reason, final Date invalidityTime) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); ParamUtil.requireNonNull("serialNumber", serialNumber); asssertMasterMode(); caName = caName.toUpperCase(); X509Ca ca = getX509Ca(caName); try { return ca.revokeCertificate(serialNumber, reason, invalidityTime, CaAuditConstants.MSGID_CA_mgmt) != null; } catch (OperationException ex) { throw new CaMgmtException(ex.getMessage(), ex); } } // method revokeCertificate @Override public boolean unrevokeCertificate(String caName, final BigInteger serialNumber) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); ParamUtil.requireNonNull("serialNumber", serialNumber); caName = caName.toUpperCase(); X509Ca ca = getX509Ca(caName); try { return ca.unrevokeCertificate(serialNumber, CaAuditConstants.MSGID_CA_mgmt) != null; } catch (OperationException ex) { throw new CaMgmtException(ex.getMessage(), ex); } } // method unrevokeCertificate @Override public boolean removeCertificate(String caName, final BigInteger serialNumber) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); ParamUtil.requireNonNull("serialNumber", serialNumber); asssertMasterMode(); caName = caName.toUpperCase(); X509Ca ca = getX509Ca(caName); if (ca == null) { return false; } try { return ca.removeCertificate(serialNumber, CaAuditConstants.MSGID_CA_mgmt) != null; } catch (OperationException ex) { throw new CaMgmtException(ex.getMessage(), ex); } } // method removeCertificate @Override public X509Certificate generateCertificate(String caName, String profileName, final byte[] encodedCsr, Date notBefore, Date notAfter) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); ParamUtil.requireNonBlank("profileName", profileName); ParamUtil.requireNonNull("encodedCsr", encodedCsr); caName = caName.toUpperCase(); profileName = profileName.toUpperCase(); AuditEvent event = new AuditEvent(new Date()); event.setApplicationName(CaAuditConstants.APPNAME); event.setName(CaAuditConstants.NAME_PERF); event.addEventType("CAMGMT_CRL_GEN_ONDEMAND"); X509Ca ca = getX509Ca(caName); CertificationRequest csr; try { csr = CertificationRequest.getInstance(encodedCsr); } catch (Exception ex) { throw new CaMgmtException("invalid CSR request. ERROR: " + ex.getMessage()); } CmpControl cmpControl = getCmpControlObject(ca.getCaInfo().getCmpControlName()); if (!securityFactory.verifyPopo(csr, cmpControl.getPopoAlgoValidator())) { throw new CaMgmtException("could not validate POP for the CSR"); } CertificationRequestInfo certTemp = csr.getCertificationRequestInfo(); Extensions extensions = null; ASN1Set attrs = certTemp.getAttributes(); for (int i = 0; i < attrs.size(); i++) { Attribute attr = Attribute.getInstance(attrs.getObjectAt(i)); if (PKCSObjectIdentifiers.pkcs_9_at_extensionRequest.equals(attr.getAttrType())) { extensions = Extensions.getInstance(attr.getAttributeValues()[0]); } } X500Name subject = certTemp.getSubject(); SubjectPublicKeyInfo publicKeyInfo = certTemp.getSubjectPublicKeyInfo(); CertTemplateData certTemplateData = new CertTemplateData(subject, publicKeyInfo, notBefore, notAfter, extensions, profileName); X509CertificateInfo certInfo; try { certInfo = ca.generateCertificate(certTemplateData, byCaRequestor, RequestType.CA, (byte[]) null, CaAuditConstants.MSGID_CA_mgmt); } catch (OperationException ex) { throw new CaMgmtException(ex.getMessage(), ex); } if (ca.getCaInfo().isSaveRequest()) { try { long dbId = ca.addRequest(encodedCsr); ca.addRequestCert(dbId, certInfo.getCert().getCertId()); } catch (OperationException ex) { LogUtil.warn(LOG, ex, "could not save request"); } } return certInfo.getCert().getCert(); } // method generateCertificate public X509Ca getX509Ca(String name) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); name = name.toUpperCase(); X509Ca ca = x509cas.get(name); if (ca == null) { throw new CaMgmtException("unknown CA " + name); } return ca; } public X509Ca getX509Ca(final NameId ident) throws CaMgmtException { ParamUtil.requireNonNull("ident", ident); X509Ca ca = x509cas.get(ident.getName()); if (ca == null) { throw new CaMgmtException("unknown CA " + ident); } return ca; } public IdentifiedX509Certprofile getIdentifiedCertprofile(final String profileName) { ParamUtil.requireNonBlank("profileName", profileName); return certprofiles.get(profileName.toUpperCase()); } public List<IdentifiedX509CertPublisher> getIdentifiedPublishersForCa(String caName) { ParamUtil.requireNonBlank("caName", caName); caName = caName.toUpperCase(); List<IdentifiedX509CertPublisher> ret = new LinkedList<>(); Set<String> publisherNames = caHasPublishers.get(caName); if (publisherNames == null) { return ret; } for (String publisherName : publisherNames) { IdentifiedX509CertPublisher publisher = publishers.get(publisherName); ret.add(publisher); } return ret; } // method getIdentifiedPublishersForCa @Override public X509Certificate generateRootCa(final X509CaEntry caEntry, String certprofileName, final byte[] encodedCsr, final BigInteger serialNumber) throws CaMgmtException { ParamUtil.requireNonNull("caEntry", caEntry); ParamUtil.requireNonBlank("certprofileName", certprofileName); ParamUtil.requireNonNull("encodedCsr", encodedCsr); certprofileName = certprofileName.toUpperCase(); int numCrls = caEntry.getNumCrls(); List<String> crlUris = caEntry.getCrlUris(); List<String> deltaCrlUris = caEntry.getDeltaCrlUris(); List<String> ocspUris = caEntry.getOcspUris(); List<String> cacertUris = caEntry.getCacertUris(); String signerType = caEntry.getSignerType(); asssertMasterMode(); if (numCrls < 0) { System.err.println("invalid numCrls: " + numCrls); return null; } int expirationPeriod = caEntry.getExpirationPeriod(); if (expirationPeriod < 0) { System.err.println("invalid expirationPeriod: " + expirationPeriod); return null; } CertificationRequest csr; try { csr = CertificationRequest.getInstance(encodedCsr); } catch (Exception ex) { System.err.println("invalid encodedCsr"); return null; } IdentifiedX509Certprofile certprofile = getIdentifiedCertprofile(certprofileName); if (certprofile == null) { throw new CaMgmtException("unknown certprofile " + certprofileName); } BigInteger serialOfThisCert = (serialNumber != null) ? serialNumber : RandomSerialNumberGenerator.getInstance().nextSerialNumber( caEntry.getSerialNoBitLen()); GenerateSelfSignedResult result; try { result = X509SelfSignedCertBuilder.generateSelfSigned(securityFactory, signerType, caEntry.getSignerConf(), certprofile, csr, serialOfThisCert, cacertUris, ocspUris, crlUris, deltaCrlUris); } catch (OperationException | InvalidConfException ex) { throw new CaMgmtException(ex.getClass().getName() + ": " + ex.getMessage(), ex); } String signerConf = result.getSignerConf(); X509Certificate caCert = result.getCert(); if ("PKCS12".equalsIgnoreCase(signerType) || "JKS".equalsIgnoreCase(signerType)) { try { signerConf = canonicalizeSignerConf(signerType, signerConf, new X509Certificate[]{caCert}, securityFactory); } catch (Exception ex) { throw new CaMgmtException(ex.getClass().getName() + ": " + ex.getMessage(), ex); } } X509CaUris caUris = new X509CaUris(cacertUris, ocspUris, crlUris, deltaCrlUris); String name = caEntry.getIdent().getName(); long nextCrlNumber = caEntry.getNextCrlNumber(); CaStatus status = caEntry.getStatus(); X509CaEntry entry = new X509CaEntry(new NameId(null, name), caEntry.getSerialNoBitLen(), nextCrlNumber, signerType, signerConf, caUris, numCrls, expirationPeriod); entry.setCertificate(caCert); entry.setCmpControlName(caEntry.getCmpControlName()); entry.setCrlSignerName(caEntry.getCrlSignerName()); entry.setDuplicateKeyPermitted(caEntry.isDuplicateKeyPermitted()); entry.setDuplicateSubjectPermitted(caEntry.isDuplicateSubjectPermitted()); entry.setExtraControl(caEntry.getExtraControl()); entry.setKeepExpiredCertInDays(caEntry.getKeepExpiredCertInDays()); entry.setMaxValidity(caEntry.getMaxValidity()); entry.setPermission(caEntry.getPermission()); entry.setResponderName(caEntry.getResponderName()); entry.setSaveRequest(caEntry.isSaveRequest()); entry.setStatus(status); entry.setValidityMode(caEntry.getValidityMode()); addCa(entry); return caCert; } // method generateRootCa private void asssertMasterMode() throws CaMgmtException { if (!masterMode) { throw new CaMgmtException("operation not allowed in slave mode"); } } void shutdownCertprofile(final IdentifiedX509Certprofile profile) { if (profile == null) { return; } try { profile.shutdown(); } catch (Exception ex) { LogUtil.warn(LOG, ex, "could not shutdown Certprofile " + profile.getIdent()); } } // method shutdownCertprofile void shutdownPublisher(final IdentifiedX509CertPublisher publisher) { if (publisher == null) { return; } try { publisher.shutdown(); } catch (Exception ex) { LogUtil.warn(LOG, ex, "could not shutdown CertPublisher " + publisher.getIdent()); } } // method shutdownPublisher CmpResponderEntryWrapper createCmpResponder(final CmpResponderEntry dbEntry) throws CaMgmtException { ParamUtil.requireNonNull("dbEntry", dbEntry); CmpResponderEntryWrapper ret = new CmpResponderEntryWrapper(); ret.setDbEntry(dbEntry); try { ret.initSigner(securityFactory); } catch (ObjectCreationException ex) { final String message = "createCmpResponder"; LOG.debug(message, ex); throw new CaMgmtException(ex.getMessage()); } return ret; } // method createCmpResponder X509CrlSignerEntryWrapper createX509CrlSigner(final X509CrlSignerEntry dbEntry) throws CaMgmtException { ParamUtil.requireNonNull("dbEntry", dbEntry); X509CrlSignerEntryWrapper signer = new X509CrlSignerEntryWrapper(); try { signer.setDbEntry(dbEntry); } catch (InvalidConfException ex) { throw new CaMgmtException("InvalidConfException: " + ex.getMessage()); } try { signer.initSigner(securityFactory); } catch (XiSecurityException | OperationException | InvalidConfException ex) { String message = "could not create CRL signer " + dbEntry.getName(); LogUtil.error(LOG, ex, message); if (ex instanceof OperationException) { throw new CaMgmtException(message + ": " + ((OperationException) ex).getErrorCode() + ", " + ex.getMessage()); } else { throw new CaMgmtException(message + ": " + ex.getMessage()); } } return signer; } // method createX509CrlSigner IdentifiedX509Certprofile createCertprofile(final CertprofileEntry dbEntry) { ParamUtil.requireNonNull("dbEntry", dbEntry); try { X509Certprofile profile = x509CertProfileFactoryRegister.newCertprofile( dbEntry.getType()); IdentifiedX509Certprofile ret = new IdentifiedX509Certprofile(dbEntry, profile); ret.setEnvParameterResolver(envParameterResolver); ret.validate(); return ret; } catch (ObjectCreationException | CertprofileException ex) { LogUtil.error(LOG, ex, "could not initialize Certprofile " + dbEntry.getIdent() + ", ignore it"); return null; } } // method createCertprofile IdentifiedX509CertPublisher createPublisher(final PublisherEntry dbEntry) throws CaMgmtException { ParamUtil.requireNonNull("dbEntry", dbEntry); String type = dbEntry.getType(); X509CertPublisher publisher; IdentifiedX509CertPublisher ret; try { if ("OCSP".equalsIgnoreCase(type)) { publisher = new OcspCertPublisher(); } else { publisher = x509CertPublisherFactoryRegister.newPublisher(type); } ret = new IdentifiedX509CertPublisher(dbEntry, publisher); ret.initialize(securityFactory.getPasswordResolver(), datasources); return ret; } catch (ObjectCreationException | CertPublisherException | RuntimeException ex) { LogUtil.error(LOG, ex, "invalid configuration for the publisher " + dbEntry.getIdent()); return null; } } // method createPublisher @Override public boolean addUser(final AddUserEntry userEntry) throws CaMgmtException { asssertMasterMode(); return queryExecutor.addUser(userEntry); } @Override public boolean changeUser(final ChangeUserEntry userEntry) throws CaMgmtException { asssertMasterMode(); return queryExecutor.changeUser(userEntry); } @Override public boolean removeUser(final String username) throws CaMgmtException { ParamUtil.requireNonBlank("username", username); asssertMasterMode(); return queryExecutor.removeUser(username.toUpperCase()); } @Override public UserEntry getUser(final String username) throws CaMgmtException { ParamUtil.requireNonBlank("username", username); return queryExecutor.getUser(username.toUpperCase()); } CaIdNameMap getIdNameMap() { return idNameMap; } @Override public X509CRL generateCrlOnDemand(String caName) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); caName = caName.toUpperCase(); X509Ca ca = getX509Ca(caName); try { return ca.generateCrlOnDemand(CaAuditConstants.MSGID_CA_mgmt); } catch (OperationException ex) { throw new CaMgmtException(ex.getMessage(), ex); } } // method generateCrlOnDemand @Override public X509CRL getCrl(String caName, final BigInteger crlNumber) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); ParamUtil.requireNonNull("crlNumber", crlNumber); caName = caName.toUpperCase(); X509Ca ca = getX509Ca(caName); try { X509CRL crl = ca.getCrl(crlNumber); if (crl == null) { LOG.warn("found no CRL for CA {} and crlNumber {}", caName, crlNumber); } return crl; } catch (OperationException ex) { throw new CaMgmtException(ex.getMessage(), ex); } } // method getCrl @Override public X509CRL getCurrentCrl(String caName) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); caName = caName.toUpperCase(); X509Ca ca = getX509Ca(caName); try { X509CRL crl = ca.getCurrentCrl(); if (crl == null) { LOG.warn("found no CRL for CA {}", caName); } return crl; } catch (OperationException ex) { throw new CaMgmtException(ex.getMessage(), ex); } } // method getCurrentCrl @Override public boolean addScep(final ScepEntry dbEntry) throws CaMgmtException { ParamUtil.requireNonNull("dbEntry", dbEntry); asssertMasterMode(); NameId caIdent = idNameMap.getCa(dbEntry.getCaIdent().getName()); if (caIdent == null) { LOG.warn("CA {} does not exist", dbEntry.getCaIdent().getName()); } dbEntry.getCaIdent().setId(caIdent.getId()); Scep scep = new Scep(dbEntry, this); boolean bo = queryExecutor.addScep(dbEntry); if (bo) { final String name = dbEntry.getName(); scepDbEntries.put(name, dbEntry); sceps.put(name, scep); } return bo; } // method addScep @Override public boolean removeScep(String name) throws CaMgmtException { ParamUtil.requireNonBlank("name", name); asssertMasterMode(); name = name.toUpperCase(); boolean bo = queryExecutor.removeScep(name); if (bo) { scepDbEntries.remove(name); sceps.remove(name); } return bo; } // method removeScep public boolean changeScep(final ChangeScepEntry scepEntry) throws CaMgmtException { ParamUtil.requireNonNull("scepEntry", scepEntry); asssertMasterMode(); String name = scepEntry.getName(); Boolean active = scepEntry.isActive(); String type = scepEntry.getResponderType(); String conf = scepEntry.getResponderConf(); String base64Cert = scepEntry.getBase64Cert(); String control = scepEntry.getControl(); if (type == null && conf == null && base64Cert == null && control == null) { return false; } Scep scep = queryExecutor.changeScep(name, scepEntry.getCaIdent(), active, type, conf, base64Cert, scepEntry.getCertProfiles(), control, this); if (scep == null) { return false; } sceps.remove(name); scepDbEntries.remove(name); scepDbEntries.put(name, scep.getDbEntry()); sceps.put(name, scep); return true; } // method changeScep @Override public ScepEntry getScepEntry(final String name) { ParamUtil.requireNonBlank("name", name); return (scepDbEntries == null) ? null : scepDbEntries.get(name.toUpperCase()); } @Override public Scep getScep(final String name) { ParamUtil.requireNonBlank("name", name); return (sceps == null) ? null : sceps.get(name.toUpperCase()); } @Override public Set<String> getScepNames() { return (scepDbEntries == null) ? null : Collections.unmodifiableSet(scepDbEntries.keySet()); } private static void assertNotNull(final String parameterName, final String parameterValue) { if (CaManager.NULL.equalsIgnoreCase(parameterValue)) { throw new IllegalArgumentException(parameterName + " must not be " + CaManager.NULL); } } private static String canonicalizeSignerConf(final String keystoreType, final String signerConf, final X509Certificate[] certChain, final SecurityFactory securityFactory) throws Exception { if (!signerConf.contains("file:") && !signerConf.contains("base64:")) { return signerConf; } ConfPairs pairs = new ConfPairs(signerConf); String keystoreConf = pairs.getValue("keystore"); String passwordHint = pairs.getValue("password"); String keyLabel = pairs.getValue("key-label"); byte[] ksBytes; if (StringUtil.startsWithIgnoreCase(keystoreConf, "file:")) { String keystoreFile = keystoreConf.substring("file:".length()); ksBytes = IoUtil.read(keystoreFile); } else if (StringUtil.startsWithIgnoreCase(keystoreConf, "base64:")) { ksBytes = Base64.decode(keystoreConf.substring("base64:".length())); } else { return signerConf; } ksBytes = securityFactory.extractMinimalKeyStore(keystoreType, ksBytes, keyLabel, securityFactory.getPasswordResolver().resolvePassword(passwordHint), certChain); pairs.putPair("keystore", "base64:" + Base64.toBase64String(ksBytes)); return pairs.getEncoded(); } // method canonicalizeSignerConf @Override public CertWithStatusInfo getCert(String caName, BigInteger serialNumber) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); ParamUtil.requireNonNull("serialNumber", serialNumber); caName = caName.toUpperCase(); X509Ca ca = getX509Ca(caName); X509CertWithRevocationInfo certInfo; try { certInfo = ca.getCertWithRevocationInfo(serialNumber); } catch (CertificateException | OperationException ex) { throw new CaMgmtException(ex.getMessage(), ex); } return (certInfo != null) ? certInfo.toCertWithStatusInfo() : new CertWithStatusInfo(); } @Override public byte[] getCertRequest(String caName, BigInteger serialNumber) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); ParamUtil.requireNonNull("serialNumber", serialNumber); caName = caName.toUpperCase(); X509Ca ca = getX509Ca(caName); try { return ca.getCertRequest(serialNumber); } catch (OperationException ex) { throw new CaMgmtException(ex.getMessage(), ex); } } @Override public List<CertListInfo> listCertificates(String caName, final X500Name subjectPattern, final Date validFrom, final Date validTo, final CertListOrderBy orderBy, final int numEntries) throws CaMgmtException { ParamUtil.requireNonBlank("caName", caName); ParamUtil.requireRange("numEntries", numEntries, 1, 1000); caName = caName.toUpperCase(); X509Ca ca = getX509Ca(caName); try { return ca.listCertificates(subjectPattern, validFrom, validTo, orderBy, numEntries); } catch (OperationException ex) { throw new CaMgmtException(ex.getMessage(), ex); } } @Override public boolean loadConf(CaConf conf) throws CaMgmtException { ParamUtil.requireNonNull("conf", conf); for (String name : conf.getCmpControlNames()) { CmpControlEntry entry = conf.getCmpControl(name); CmpControlEntry entryB = cmpControlDbEntries.get(name); if (entryB != null) { if (entry.equals(entryB)) { LOG.info("ignore existed CMP control {}", name); } else { String msg = "CMP control " + name + " existed, could not re-added it"; LOG.error(msg); throw new CaMgmtException(msg); } } else { if (addCmpControl(entry)) { LOG.info("added CMP control {}", name); } else { String msg = "could not add CMP control " + name; LOG.error(msg); throw new CaMgmtException(msg); } } } for (String name : conf.getResponderNames()) { CmpResponderEntry entry = conf.getResponder(name); CmpResponderEntry entryB = responderDbEntries.get(name); if (entryB != null) { if (entry.equals(entryB)) { LOG.info("ignore existed CMP responder {}", name); } else { String msg = "CMP responder " + name + " existed, could not re-added it"; LOG.error(msg); throw new CaMgmtException(msg); } } else { if (addResponder(entry)) { LOG.info("added CMP responder {}", name); } else { String msg = "could not add CMP responder " + name; LOG.error(msg); throw new CaMgmtException(msg); } } } for (String name : conf.getEnvironmentNames()) { String entry = conf.getEnvironment(name); String entryB = envParameterResolver.getEnvParam(name); if (entryB != null) { if (entry.equals(entryB)) { LOG.info("ignore existed environment parameter {}", name); } else { String msg = "environment parameter " + name + " existed, could not re-added it"; LOG.error(msg); throw new CaMgmtException(msg); } } else { if (addEnvParam(name, entry)) { LOG.info("could not add environment parameter {}", name); } else { String msg = "could not add environment parameter " + name; LOG.error(msg); throw new CaMgmtException(msg); } } } for (String name : conf.getCrlSignerNames()) { X509CrlSignerEntry entry = conf.getCrlSigner(name); X509CrlSignerEntry entryB = crlSignerDbEntries.get(name); if (entryB != null) { if (entry.equals(entryB)) { LOG.info("ignore existed CRL signer {}", name); } else { String msg = "CRL signer " + name + " existed, could not re-added it"; LOG.error(msg); throw new CaMgmtException(msg); } } else { if (addCrlSigner(entry)) { LOG.info("added CRL signer {}", name); } else { String msg = "could not add CRL signer " + name; LOG.error(msg); throw new CaMgmtException(msg); } } } for (String name : conf.getCrlSignerNames()) { X509CrlSignerEntry entry = conf.getCrlSigner(name); X509CrlSignerEntry entryB = crlSignerDbEntries.get(name); if (entryB != null) { if (entry.equals(entryB)) { LOG.info("ignore existed CRL signer {}", name); } else { String msg = "CRL signer " + name + " existed, could not re-added it"; LOG.error(msg); throw new CaMgmtException(msg); } } else { if (addCrlSigner(entry)) { LOG.info("added CRL signer {}", name); } else { String msg = "could not add CRL signer " + name; LOG.error(msg); throw new CaMgmtException(msg); } } } for (String name : conf.getRequestorNames()) { CmpRequestorEntry entry = conf.getRequestor(name); CmpRequestorEntry entryB = requestorDbEntries.get(name); if (entryB != null) { if (entry.equals(entryB)) { LOG.info("ignore existed CMP requestor {}", name); continue; } else { String msg = "CMP requestor " + name + " existed, could not re-added it"; LOG.error(msg); throw new CaMgmtException(msg); } } if (addRequestor(entry)) { LOG.info("added CMP requestor {}", name); } else { String msg = "could not add CMP requestor " + name; LOG.error(msg); throw new CaMgmtException(msg); } } for (String name : conf.getPublisherNames()) { PublisherEntry entry = conf.getPublisher(name); PublisherEntry entryB = publisherDbEntries.get(name); if (entryB != null) { if (entry.equals(entryB)) { LOG.info("ignore existed publisher {}", name); continue; } else { String msg = "publisher " + name + " existed, could not re-added it"; LOG.error(msg); throw new CaMgmtException(msg); } } if (addPublisher(entry)) { LOG.info("added publisher {}", name); } else { String msg = "could not add publisher " + name; LOG.error(msg); throw new CaMgmtException(msg); } } for (String name : conf.getCertProfileNames()) { CertprofileEntry entry = conf.getCertProfile(name); CertprofileEntry entryB = certprofileDbEntries.get(name); if (entryB != null) { if (entry.equals(entryB)) { LOG.info("ignore existed certProfile {}", name); } else { String msg = "certProfile " + name + " existed, could not re-added it"; LOG.error(msg); throw new CaMgmtException(msg); } } else { if (addCertprofile(entry)) { LOG.info("added certProfile {}", name); } else { String msg = "could not add certProfile " + name; LOG.error(msg); throw new CaMgmtException(msg); } } } for (String name : conf.getCertProfileNames()) { CertprofileEntry entry = conf.getCertProfile(name); CertprofileEntry entryB = certprofileDbEntries.get(name); if (entryB != null) { if (entry.equals(entryB)) { LOG.info("ignore existed certProfile {}", name); } else { String msg = "certProfile " + name + " existed, could not re-added it"; LOG.error(msg); throw new CaMgmtException(msg); } } else { if (addCertprofile(entry)) { LOG.info("added certProfile {}", name); } else { String msg = "could not add certProfile " + name; LOG.error(msg); throw new CaMgmtException(msg); } } } for (String caName : conf.getCaNames()) { SingleCaConf scc = conf.getCa(caName); GenSelfIssued genSelfIssued = scc.getGenSelfIssued(); CaEntry caEntry = scc.getCaEntry(); if (caEntry != null) { if (! (caEntry instanceof X509CaEntry)) { throw new CaMgmtException("Unsupported CaEntry " + caName + " (only X509CaEntry is supported"); } X509CaEntry entry = (X509CaEntry) caEntry; if (caInfos.containsKey(caName)) { CaEntry entryB = caInfos.get(caName).getCaEntry(); if (entry.getCertificate() == null && genSelfIssued != null) { SignerConf signerConf = new SignerConf(entry.getSignerConf()); ConcurrentContentSigner signer; try { signer = securityFactory.createSigner(entry.getSignerType(), signerConf, (X509Certificate) null); } catch (ObjectCreationException ex) { throw new CaMgmtException("could not create signer for CA " + caName, ex); } entry.setCertificate(signer.getCertificate()); } if (entry.equals(entryB, true)) { LOG.info("ignore existed CA {}", caName); } else { String msg = "CA " + caName + " existed, could not re-added it"; LOG.error(msg); throw new CaMgmtException(msg); } } else { if (genSelfIssued != null) { X509Certificate cert = generateRootCa(entry, genSelfIssued.getProfile(), genSelfIssued.getCsr(), genSelfIssued.getSerialNumber()); LOG.info("generated root CA {}", caName); String fn = genSelfIssued.getCertFilename(); if (fn != null) { try { IoUtil.save(fn, cert.getEncoded()); LOG.info("saved generated certificate of root CA {} to {}", caName, fn); } catch (CertificateEncodingException ex) { LogUtil.error(LOG, ex, "could not encode certificate of CA " + caName); } catch (IOException ex) { LogUtil.error(LOG, ex, "error while saving certificate of root CA " + caName + " to " + fn); } } } else if (addCa(entry)) { LOG.info("added CA {}", caName); } else { String msg = "could not add CA " + caName; LOG.error(msg); throw new CaMgmtException(msg); } } } if (scc.getAliases() != null) { Set<String> aliasesB = getAliasesForCa(caName); for (String aliasName : scc.getAliases()) { if (aliasesB != null && aliasesB.contains(aliasName)) { LOG.info("ignored adding existing CA alias {} to CA {}", aliasName, caName); } else { if (addCaAlias(aliasName, caName)) { LOG.info("associated alias {} to CA {}", aliasName, caName); } else { String msg = "could not associate alias " + aliasName + " to CA " + caName; LOG.error(msg); throw new CaMgmtException(msg); } } } } if (scc.getProfileNames() != null) { Set<String> profilesB = caHasProfiles.get(caName); for (String profileName : scc.getProfileNames()) { if (profilesB != null && profilesB.contains(profileName)) { LOG.info("ignored adding certprofile {} to CA {}", profileName, caName); } else { if (addCertprofileToCa(profileName, caName)) { LOG.info("added certprofile {} to CA {}", profileName, caName); } else { String msg = "could not add certprofile " + profileName + " to CA " + caName; LOG.error(msg); throw new CaMgmtException(msg); } } } } if (scc.getPublisherNames() != null) { Set<String> publishersB = caHasPublishers.get(caName); for (String publisherName : scc.getPublisherNames()) { if (publishersB != null && publishersB.contains(publisherName)) { LOG.info("ignored adding publisher {} to CA {}", publisherName, caName); } else { if (addPublisherToCa(publisherName, caName)) { LOG.info("added publisher {} to CA {}", publisherName, caName); } else { String msg = "could not add publisher " + publisherName + " to CA " + caName; LOG.error(msg); throw new CaMgmtException(msg); } } } } if (scc.getRequestors() != null) { Set<CaHasRequestorEntry> requestorsB = caHasRequestors.get(caName); for (CaHasRequestorEntry requestor : scc.getRequestors()) { String requestorName = requestor.getRequestorIdent().getName(); CaHasRequestorEntry requestorB = null; if (requestorsB != null) { for (CaHasRequestorEntry m : requestorsB) { if (m.getRequestorIdent().getName().equals(requestorName)) { requestorB = m; break; } } } if (requestorB != null) { if (requestor.equals(requestorB)) { LOG.info("ignored adding requestor {} to CA {}", requestorName, caName); } else { String msg = "could not add requestor " + requestorName + " to CA" + caName; LOG.error(msg); throw new CaMgmtException(msg); } } else { if (addRequestorToCa(requestor, caName)) { LOG.info("added publisher {} to CA {}", requestorName, caName); } else { String msg = "could not add publisher " + requestorName + " to CA " + caName; LOG.error(msg); throw new CaMgmtException(msg); } } } } // scc.getRequestors() } // cas for (String name : conf.getScepNames()) { ScepEntry entry = conf.getScep(name); ScepEntry entryB = scepDbEntries.get(name); if (entryB != null) { if (entry.equals(entryB)) { LOG.error("ignore existed SCEP {}", name); continue; } else { String msg = "SCEP " + name + " existed, could not re-added it"; LOG.error(msg); throw new CaMgmtException(msg); } } else { if (addScep(entry)) { LOG.info("added SCEP {}", name); } else { String msg = "could not add SCEP " + name; LOG.error(msg); throw new CaMgmtException(msg); } } } return true; } @Override public boolean exportConf(@NonNull String zipFilename, @Nullable List<String> caNames) throws CaMgmtException, IOException { List<String> upperCaNames; if (caNames == null) { upperCaNames = null; } else { upperCaNames = new ArrayList<>(caNames.size()); for (String name : caNames) { upperCaNames.add(name); } } File zipFile = new File(zipFilename); if (zipFile.exists()) { throw new IOException("File " + zipFilename + " exists."); } CAConfType root = new CAConfType(); root.setVersion(1); ZipOutputStream zipStream = getZipOutputStream(zipFile); try { Set<String> includeCaNames = new HashSet<>(); Set<String> includeCmpControlNames = new HashSet<>(); Set<String> includeResponderNames = new HashSet<>(); Set<String> includeRequestorNames = new HashSet<>(); Set<String> includeProfileNames = new HashSet<>(); Set<String> includePublisherNames = new HashSet<>(); Set<String> includeCrlSignerNames = new HashSet<>(); // cas if (CollectionUtil.isNonEmpty(x509cas)) { List<CaType> list = new LinkedList<>(); for (String name : x509cas.keySet()) { if (upperCaNames != null && !upperCaNames.contains(name)) { continue; } includeCaNames.add(name); CaType jaxb = new CaType(); jaxb.setName(name); Set<String> strs = getAliasesForCa(name); if (CollectionUtil.isNonEmpty(strs)) { jaxb.setAliases(createStrings(strs)); } strs = caHasProfiles.get(name); if (CollectionUtil.isNonEmpty(strs)) { includeProfileNames.addAll(strs); jaxb.setProfiles(createStrings(strs)); } strs = caHasPublishers.get(name); if (CollectionUtil.isNonEmpty(strs)) { includePublisherNames.addAll(strs); jaxb.setPublishers(createStrings(strs)); } Set<CaHasRequestorEntry> requestors = caHasRequestors.get(name); if (CollectionUtil.isNonEmpty(requestors)) { jaxb.setRequestors(new CaType.Requestors()); for (CaHasRequestorEntry m : requestors) { String requestorName = m.getRequestorIdent().getName(); includeRequestorNames.add(requestorName); CaHasRequestorType jaxb2 = new CaHasRequestorType(); jaxb2.setRequestorName(requestorName); jaxb2.setRa(m.isRa()); jaxb2.setProfiles(createStrings(m.getProfiles())); jaxb2.setPermission(m.getPermission()); jaxb.getRequestors().getRequestor().add(jaxb2); } } X509CaEntry entry = x509cas.get(name).getCaInfo().getCaEntry(); X509CaInfoType ciJaxb = new X509CaInfoType(); ciJaxb.setCacertUris(createStrings(entry.getCacertUris())); byte[] certBytes; try { certBytes = entry.getCertificate().getEncoded(); } catch (CertificateEncodingException ex) { throw new CaMgmtException("could not encode CA certificate " + name); } ciJaxb.setCert(createFileOrBinary(zipStream, certBytes, "files/ca-" + name + "-cert.der")); if (entry.getCmpControlName() != null) { includeCmpControlNames.add(entry.getCmpControlName()); ciJaxb.setCmpcontrolName(entry.getCmpControlName()); } if (entry.getCrlSignerName() != null) { includeCrlSignerNames.add(entry.getCrlSignerName()); ciJaxb.setCrlsignerName(entry.getCrlSignerName()); } ciJaxb.setCrlUris(createStrings(entry.getCrlUris())); ciJaxb.setDeltacrlUris(createStrings(entry.getDeltaCrlUris())); ciJaxb.setDuplicateKey(entry.isDuplicateKeyPermitted()); ciJaxb.setDuplicateSubject(entry.isDuplicateSubjectPermitted()); ciJaxb.setExpirationPeriod(entry.getExpirationPeriod()); ciJaxb.setExtraControl( createFileOrValue(zipStream, entry.getExtraControl(), "files/ca-" + name + "-extracontrol.conf")); ciJaxb.setKeepExpiredCertDays(entry.getKeepExpiredCertInDays()); ciJaxb.setMaxValidity(entry.getMaxValidity().toString()); ciJaxb.setNextCrlNo(entry.getNextCrlNumber()); ciJaxb.setNumCrls(entry.getNumCrls()); ciJaxb.setOcspUris(createStrings(entry.getOcspUris())); ciJaxb.setPermission(entry.getPermission()); if (entry.getResponderName() != null) { includeResponderNames.add(entry.getResponderName()); ciJaxb.setResponderName(entry.getResponderName()); } ciJaxb.setSaveReq(entry.isSaveRequest()); ciJaxb.setSignerConf(createFileOrValue(zipStream, entry.getSignerConf(), "files/ca-" + name + "-signerconf.conf")); ciJaxb.setSignerType(entry.getSignerType()); ciJaxb.setSnSize(entry.getSerialNoBitLen()); ciJaxb.setStatus(entry.getStatus().getStatus()); ciJaxb.setValidityMode(entry.getValidityMode().name()); jaxb.setCaInfo(new CaType.CaInfo()); jaxb.getCaInfo().setX509Ca(ciJaxb); list.add(jaxb); } if (!list.isEmpty()) { root.setCas(new CAConfType.Cas()); root.getCas().getCa().addAll(list); } } // cmp controls if (CollectionUtil.isNonEmpty(cmpControlDbEntries)) { List<CmpcontrolType> list = new LinkedList<>(); for (String name : cmpControlDbEntries.keySet()) { if (!includeCmpControlNames.contains(name)) { continue; } CmpcontrolType jaxb = new CmpcontrolType(); CmpControlEntry entry = cmpControlDbEntries.get(name); jaxb.setName(name); jaxb.setConf(createFileOrValue(zipStream, entry.getConf(), "files/cmpcontrol-" + name + ".conf")); list.add(jaxb); } if (!list.isEmpty()) { root.setCmpcontrols(new CAConfType.Cmpcontrols()); root.getCmpcontrols().getCmpcontrol().addAll(list); } } // responders if (CollectionUtil.isNonEmpty(responderDbEntries)) { List<ResponderType> list = new LinkedList<>(); for (String name : responderDbEntries.keySet()) { if (!includeResponderNames.contains(name)) { continue; } CmpResponderEntry entry = responderDbEntries.get(name); ResponderType jaxb = new ResponderType(); jaxb.setName(name); jaxb.setType(entry.getType()); jaxb.setConf(createFileOrValue(zipStream, entry.getConf(), "files/responder-" + name + ".conf")); jaxb.setCert(createFileOrBase64Value(zipStream, entry.getBase64Cert(), "files/responder-" + name + ".der")); list.add(jaxb); } if (!list.isEmpty()) { root.setResponders(new CAConfType.Responders()); root.getResponders().getResponder().addAll(list); } } // environments Set<String> names = envParameterResolver.getAllParameterNames(); if (CollectionUtil.isNonEmpty(names)) { List<NameValueType> list = new LinkedList<>(); for (String name : names) { if (ENV_EPOCH.equalsIgnoreCase(name)) { continue; } NameValueType jaxb = new NameValueType(); jaxb.setName(name); jaxb.setValue(envParameterResolver.getEnvParam(name)); list.add(jaxb); } if (!list.isEmpty()) { root.setEnvironments(new CAConfType.Environments()); root.getEnvironments().getEnvironment().addAll(list); } } // crlsigners if (CollectionUtil.isNonEmpty(crlSignerDbEntries)) { List<CrlsignerType> list = new LinkedList<>(); for (String name : crlSignerDbEntries.keySet()) { if (!includeCrlSignerNames.contains(name)) { continue; } X509CrlSignerEntry entry = crlSignerDbEntries.get(name); CrlsignerType jaxb = new CrlsignerType(); jaxb.setName(name); jaxb.setSignerType(entry.getType()); jaxb.setSignerConf(createFileOrValue(zipStream, entry.getConf(), "files/crlsigner-" + name + ".conf")); jaxb.setSignerCert(createFileOrBase64Value(zipStream, entry.getBase64Cert(), "files/crlsigner-" + name + ".der")); jaxb.setCrlControl(entry.getCrlControl()); list.add(jaxb); } if (!list.isEmpty()) { root.setCrlsigners(new CAConfType.Crlsigners()); root.getCrlsigners().getCrlsigner().addAll(list); } } // requestors if (CollectionUtil.isNonEmpty(requestorDbEntries)) { List<RequestorType> list = new LinkedList<>(); for (String name : requestorDbEntries.keySet()) { if (!includeRequestorNames.contains(name)) { continue; } CmpRequestorEntry entry = requestorDbEntries.get(name); RequestorType jaxb = new RequestorType(); jaxb.setName(name); jaxb.setCert(createFileOrBase64Value(zipStream, entry.getBase64Cert(), "files/requestor-" + name + ".der")); list.add(jaxb); } if (!list.isEmpty()) { root.setRequestors(new CAConfType.Requestors()); root.getRequestors().getRequestor().addAll(list); } } // publishers if (CollectionUtil.isNonEmpty(publisherDbEntries)) { List<PublisherType> list = new LinkedList<>(); for (String name : publisherDbEntries.keySet()) { if (!includePublisherNames.contains(name)) { continue; } PublisherEntry entry = publisherDbEntries.get(name); PublisherType jaxb = new PublisherType(); jaxb.setName(name); jaxb.setType(entry.getType()); jaxb.setConf(createFileOrValue(zipStream, entry.getConf(), "files/publisher-" + name + ".conf")); list.add(jaxb); } if (!list.isEmpty()) { root.setPublishers(new CAConfType.Publishers()); root.getPublishers().getPublisher().addAll(list); } } // profiles if (CollectionUtil.isNonEmpty(certprofileDbEntries)) { List<ProfileType> list = new LinkedList<>(); for (String name : certprofileDbEntries.keySet()) { if (!includeProfileNames.contains(name)) { continue; } CertprofileEntry entry = certprofileDbEntries.get(name); ProfileType jaxb = new ProfileType(); jaxb.setName(name); jaxb.setType(entry.getType()); jaxb.setConf(createFileOrValue(zipStream, entry.getConf(), "files/certprofile-" + name + ".conf")); list.add(jaxb); } if (!list.isEmpty()) { root.setProfiles(new CAConfType.Profiles()); root.getProfiles().getProfile().addAll(list); } } // sceps if (CollectionUtil.isNonEmpty(scepDbEntries)) { List<ScepType> list = new LinkedList<>(); for (String name : scepDbEntries.keySet()) { if (!includeCaNames.contains(name)) { continue; } ScepEntry entry = scepDbEntries.get(name); ScepType jaxb = new ScepType(); jaxb.setCaName(name); jaxb.setResponderType(entry.getResponderType()); jaxb.setResponderConf(createFileOrValue(zipStream, entry.getResponderConf(), "files/scep-" + name + ".conf")); jaxb.setResponderCert(createFileOrBase64Value(zipStream, entry.getBase64Cert(), "files/scep-" + name + ".der")); jaxb.setControl(entry.getControl()); list.add(jaxb); } if (!list.isEmpty()) { root.setSceps(new CAConfType.Sceps()); root.getSceps().getScep().addAll(list); } } // add the CAConf XML file ByteArrayOutputStream bout = new ByteArrayOutputStream(); try { CaConf.marshal(root, bout); } catch (JAXBException | SAXException ex) { LogUtil.error(LOG, ex, "could not marshal CAConf"); throw new CaMgmtException("could not marshal CAConf: " + ex.getMessage(), ex); } finally { bout.flush(); } zipStream.putNextEntry(new ZipEntry("caconf.xml")); try { zipStream.write(bout.toByteArray()); } finally { zipStream.closeEntry(); } } finally { zipStream.close(); } return true; } private static FileOrValueType createFileOrValue(final ZipOutputStream zipStream, final String content, final String fileName) throws IOException { if (StringUtil.isBlank(content)) { return null; } FileOrValueType ret = new FileOrValueType(); if (content.length() < 256) { ret.setValue(content); } else { ret.setFile(fileName); ZipEntry certZipEntry = new ZipEntry(fileName); zipStream.putNextEntry(certZipEntry); try { zipStream.write(content.getBytes("UTF-8")); } finally { zipStream.closeEntry(); } } return ret; } private static FileOrBinaryType createFileOrBase64Value(final ZipOutputStream zipStream, final String b64Content, final String fileName) throws IOException { if (StringUtil.isBlank(b64Content)) { return null; } return createFileOrBinary(zipStream, Base64.decode(b64Content), fileName); } private static FileOrBinaryType createFileOrBinary(final ZipOutputStream zipStream, final byte[] content, final String fileName) throws IOException { if (content == null || content.length == 0) { return null; } FileOrBinaryType ret = new FileOrBinaryType(); if (content.length < 256) { ret.setBinary(content); } else { ret.setFile(fileName); ZipEntry certZipEntry = new ZipEntry(fileName); zipStream.putNextEntry(certZipEntry); try { zipStream.write(content); } finally { zipStream.closeEntry(); } } return ret; } private static ZipOutputStream getZipOutputStream(final File zipFile) throws FileNotFoundException { ParamUtil.requireNonNull("zipFile", zipFile); BufferedOutputStream out = new BufferedOutputStream( new FileOutputStream(zipFile), 1048576); // 1M ZipOutputStream zipOutStream = new ZipOutputStream(out); zipOutStream.setLevel(Deflater.BEST_SPEED); return zipOutStream; } private static StringsType createStrings(Collection<String> strs) { if (CollectionUtil.isEmpty(strs)) { return null; } StringsType ret = new StringsType(); for (String str : strs) { ret.getStr().add(str); } return ret; } }