/* * * 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.scep.serveremulator; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.util.Date; import org.bouncycastle.asn1.x500.X500Name; import org.bouncycastle.asn1.x509.BasicConstraints; import org.bouncycastle.asn1.x509.Certificate; import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.cert.CertIOException; import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.jce.X509KeyUsage; import org.bouncycastle.operator.ContentSigner; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; import org.xipki.commons.audit.internal.Slf4jAuditServiceImpl; import org.xipki.commons.common.util.ParamUtil; import org.xipki.pki.scep.crypto.ScepHashAlgoType; import org.xipki.pki.scep.message.CaCaps; import org.xipki.pki.scep.util.ScepUtil; /** * @author Lijun Liao * @since 2.0.0 */ public class ScepServer { private final String name; private final CaCaps caCaps; private final boolean withRa; private final boolean withNextCa; private final boolean generateCrl; private final ScepControl control; private Long maxSigningTimeBiasInMs; private ScepServlet servlet; private Certificate caCert; private Certificate raCert; private Certificate nextCaCert; private Certificate nextRaCert; public ScepServer(final String name, final CaCaps caCaps, final boolean withRa, final boolean withNextCa, final boolean generateCrl, final ScepControl control) { this.name = ParamUtil.requireNonBlank("name", name); this.caCaps = ParamUtil.requireNonNull("caCaps", caCaps); this.control = ParamUtil.requireNonNull("control", control); this.withRa = withRa; this.withNextCa = withNextCa; this.generateCrl = generateCrl; } public String getName() { return name; } public void setMaxSigningTimeBias(final long ms) { this.maxSigningTimeBiasInMs = ms; } public ScepServlet getServlet() throws Exception { if (servlet != null) { return servlet; } KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA"); X500Name rcaSubject; kpGen.initialize(2048); KeyPair keypair = kpGen.generateKeyPair(); // CHECKSTYLE:SKIP PrivateKey rcaKey = keypair.getPrivate(); rcaSubject = new X500Name("CN=RCA1, OU=emulator, O=xipki.org, C=DE"); kpGen.initialize(2048); keypair = kpGen.generateKeyPair(); SubjectPublicKeyInfo pkInfo = ScepUtil.createSubjectPublicKeyInfo(keypair.getPublic()); X500Name subject = new X500Name("CN=CA1, OU=emulator, O=xipki.org, C=DE"); this.caCert = issueSubCaCert(rcaKey, rcaSubject, pkInfo, subject, BigInteger.valueOf(2), new Date(System.currentTimeMillis() - 10 * CaEmulator.MIN_IN_MS)); CaEmulator ca = new CaEmulator(keypair.getPrivate(), this.caCert, generateCrl); RaEmulator ra = null; if (withRa) { kpGen.initialize(2048); keypair = kpGen.generateKeyPair(); pkInfo = ScepUtil.createSubjectPublicKeyInfo(keypair.getPublic()); subject = new X500Name("CN=RA1, OU=emulator, O=xipki.org, C=DE"); this.raCert = ca.generateCert(pkInfo, subject); ra = new RaEmulator(keypair.getPrivate(), this.raCert); } NextCaAndRa nextCaAndRa = null; if (withNextCa) { kpGen.initialize(2048); keypair = kpGen.generateKeyPair(); pkInfo = ScepUtil.createSubjectPublicKeyInfo(keypair.getPublic()); subject = new X500Name("CN=CA2, OU=emulator, O=xipki.org, C=DE"); Date startTime = new Date(System.currentTimeMillis() + 365 * CaEmulator.DAY_IN_MS); this.nextCaCert = issueSubCaCert(rcaKey, rcaSubject, pkInfo, subject, BigInteger.valueOf(2), startTime); CaEmulator tmpCa = new CaEmulator(keypair.getPrivate(), this.nextCaCert, generateCrl); if (withRa) { kpGen.initialize(2048); keypair = kpGen.generateKeyPair(); pkInfo = ScepUtil.createSubjectPublicKeyInfo(keypair.getPublic()); subject = new X500Name("CN=RA2, OU=emulator, O=xipki.org, C=DE"); Date raStartTime = new Date(startTime.getTime() + 10 * CaEmulator.DAY_IN_MS); this.nextRaCert = tmpCa.generateCert(pkInfo, subject, raStartTime); } // end if(withRA) nextCaAndRa = new NextCaAndRa(this.nextCaCert, this.nextRaCert); } // end if(withNextCA) ScepResponder scepResponder = new ScepResponder(caCaps, ca, ra, nextCaAndRa, control); if (maxSigningTimeBiasInMs != null) { scepResponder.setMaxSigningTimeBias(maxSigningTimeBiasInMs); } this.servlet = new ScepServlet(scepResponder); this.servlet.setAuditService(new Slf4jAuditServiceImpl()); return this.servlet; } // method getServlet public Certificate getCaCert() { return caCert; } public Certificate getRaCert() { return raCert; } public Certificate getNextCaCert() { return nextCaCert; } public Certificate getNextRaCert() { return nextRaCert; } public boolean isWithRa() { return withRa; } public boolean isWithNextCa() { return withNextCa; } public boolean isGenerateCrl() { return generateCrl; } private static Certificate issueSubCaCert(final PrivateKey rcaKey, final X500Name issuer, final SubjectPublicKeyInfo pubKeyInfo, final X500Name subject, final BigInteger serialNumber, final Date startTime) throws CertIOException, OperatorCreationException { Date notAfter = new Date(startTime.getTime() + CaEmulator.DAY_IN_MS * 3650); X509v3CertificateBuilder certGenerator = new X509v3CertificateBuilder(issuer, serialNumber, startTime, notAfter, subject, pubKeyInfo); X509KeyUsage ku = new X509KeyUsage(X509KeyUsage.keyCertSign | X509KeyUsage.cRLSign); certGenerator.addExtension(Extension.keyUsage, true, ku); BasicConstraints bc = new BasicConstraints(0); certGenerator.addExtension(Extension.basicConstraints, true, bc); String signatureAlgorithm = ScepUtil.getSignatureAlgorithm(rcaKey, ScepHashAlgoType.SHA256); ContentSigner contentSigner = new JcaContentSignerBuilder(signatureAlgorithm).build(rcaKey); return certGenerator.build(contentSigner).toASN1Structure(); } }