/**
* DSS - Digital Signature Services
* Copyright (C) 2015 European Commission, provided under the CEF programme
*
* This file is part of the "DSS - Digital Signature Services" project.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package eu.europa.esig.dss.test.gen;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import eu.europa.esig.dss.DSSException;
import eu.europa.esig.dss.EncryptionAlgorithm;
import eu.europa.esig.dss.SignatureAlgorithm;
import eu.europa.esig.dss.test.mock.MockPrivateKeyEntry;
import eu.europa.esig.dss.token.DSSPrivateKeyEntry;
import eu.europa.esig.dss.x509.CertificateToken;
public class CertificateService {
private static final BouncyCastleProvider SECURITY_PROVIDER = new BouncyCastleProvider();
private static final int MAX = Integer.MAX_VALUE;
static {
Security.addProvider(SECURITY_PROVIDER);
}
// Annotation for error_probe
@SuppressWarnings("InsecureCryptoUsage")
public KeyPair generateKeyPair(final EncryptionAlgorithm algorithm) throws GeneralSecurityException {
if (algorithm == EncryptionAlgorithm.ECDSA) {
return generateECDSAKeyPair();
} else if (algorithm == EncryptionAlgorithm.RSA) {
KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA", SECURITY_PROVIDER);
keyGenerator.initialize(2048);
return keyGenerator.generateKeyPair();
} else if (algorithm == EncryptionAlgorithm.DSA) {
KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("DSA", SECURITY_PROVIDER);
keyGenerator.initialize(1024);
return keyGenerator.generateKeyPair();
}
throw new DSSException("Unknown algo : " + algorithm);
}
private KeyPair generateECDSAKeyPair() throws GeneralSecurityException {
ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("prime256v1");
KeyPairGenerator generator = KeyPairGenerator.getInstance("ECDSA", SECURITY_PROVIDER);
generator.initialize(ecSpec, new SecureRandom());
return generator.generateKeyPair();
}
public MockPrivateKeyEntry generateCertificateChain(final SignatureAlgorithm algorithm, final MockPrivateKeyEntry rootEntry, Date notBefore, Date notAfter)
throws Exception {
X500Name rootName = new JcaX509CertificateHolder(rootEntry.getCertificate().getCertificate()).getSubject();
KeyPair childKeyPair = generateKeyPair(algorithm.getEncryptionAlgorithm());
X500Name childSubject = new X500Name("CN=SignerFake,O=DSS-test");
CertificateToken child = generateRootCertificateWithCrl(algorithm, childSubject, rootName, rootEntry.getPrivateKey(), childKeyPair.getPublic(),
notBefore, notAfter);
CertificateToken[] chain = createChildCertificateChain(rootEntry);
return new MockPrivateKeyEntry(algorithm.getEncryptionAlgorithm(), child, chain, childKeyPair.getPrivate());
}
public MockPrivateKeyEntry generateCertificateChain(final SignatureAlgorithm algorithm, boolean rootCrl) throws Exception {
MockPrivateKeyEntry rootEntry = generateSelfSignedCertificate(algorithm, rootCrl);
Date notBefore = new Date(System.currentTimeMillis() - (24 * 60 * 60 * 1000)); // yesterday
Date notAfter = new Date(System.currentTimeMillis() + MAX); // 1000d
return generateCertificateChain(algorithm, rootEntry, notBefore, notAfter);
}
public MockPrivateKeyEntry generateCertificateChain(final SignatureAlgorithm algorithm) throws Exception {
return generateCertificateChain(algorithm, true);
}
public MockPrivateKeyEntry generateCertificateChain(final SignatureAlgorithm algorithm, MockPrivateKeyEntry rootEntry) throws Exception {
Date notBefore = new Date(System.currentTimeMillis() - (24 * 60 * 60 * 1000)); // yesterday
Date notAfter = new Date(System.currentTimeMillis() + MAX); // 1000d
return generateCertificateChain(algorithm, rootEntry, notBefore, notAfter);
}
public MockPrivateKeyEntry generateExpiredCertificateChain(final SignatureAlgorithm algorithm, boolean rootCrl) throws Exception {
MockPrivateKeyEntry rootEntry = generateSelfSignedCertificate(algorithm, rootCrl);
Date notBefore = new Date(System.currentTimeMillis() - (10 * 24 * 60 * 60 * 1000)); // -10d
Date notAfter = new Date(System.currentTimeMillis() - (24 * 60 * 60 * 1000)); // yesterday
return generateCertificateChain(algorithm, rootEntry, notBefore, notAfter);
}
public MockPrivateKeyEntry generateSelfSignedCertificate(final SignatureAlgorithm algorithm, boolean rootCrl) throws Exception {
KeyPair keyPair = generateKeyPair(algorithm.getEncryptionAlgorithm());
X500Name issuer = new X500Name("CN=RootSelfSignedFake,O=DSS-test");
Date notBefore = new Date(System.currentTimeMillis() - (24 * 60 * 60 * 1000)); // yesterday
Date notAfter = new Date(System.currentTimeMillis() + MAX); // 1000d
CertificateToken certificate = null;
if (rootCrl) {
certificate = generateRootCertificateWithCrl(algorithm, issuer, issuer, keyPair.getPrivate(), keyPair.getPublic(), notBefore, notAfter);
} else {
certificate = generateRootCertificateWithoutCrl(algorithm, issuer, issuer, keyPair.getPrivate(), keyPair.getPublic(), notBefore, notAfter);
}
return new MockPrivateKeyEntry(algorithm.getEncryptionAlgorithm(), certificate, keyPair.getPrivate());
}
public MockPrivateKeyEntry generateTspCertificate(final SignatureAlgorithm algorithm) throws Exception {
KeyPair keyPair = generateKeyPair(algorithm.getEncryptionAlgorithm());
X500Name issuer = new X500Name("CN=RootIssuerTSPFake,O=DSS-test");
X500Name subject = new X500Name("CN=RootSubjectTSP,O=DSS-test");
final Date notBefore = new Date(System.currentTimeMillis() - (24 * 60 * 60 * 1000)); // yesterday
final Date notAfter = new Date(System.currentTimeMillis() + MAX); // 1000d
// generate certificate
CertificateToken cert = generateTspCertificate(algorithm, keyPair, issuer, subject, notBefore, notAfter);
return new MockPrivateKeyEntry(algorithm.getEncryptionAlgorithm(), cert, keyPair.getPrivate());
}
/**
* Generate a CertificateToken suitable for a TSA
*
* @param algorithm
* @param keyPair
* @param issuer
* @param subject
* @param notBefore
* @param notAfter
* @return
* @throws CertIOException
* @throws OperatorCreationException
* @throws CertificateException
* @throws IOException
*/
public CertificateToken generateTspCertificate(final SignatureAlgorithm algorithm, KeyPair keyPair, X500Name issuer, X500Name subject, final Date notBefore,
final Date notAfter) throws CertIOException, OperatorCreationException, CertificateException, IOException {
final SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
final X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(issuer,
new BigInteger("" + new Random().nextInt(10) + System.currentTimeMillis()), notBefore, notAfter, subject, keyInfo);
certBuilder.addExtension(Extension.extendedKeyUsage, true, new ExtendedKeyUsage(KeyPurposeId.id_kp_timeStamping));
final ContentSigner signer = new JcaContentSignerBuilder(algorithm.getJCEId()).setProvider(BouncyCastleProvider.PROVIDER_NAME)
.build(keyPair.getPrivate());
final X509CertificateHolder holder = certBuilder.build(signer);
final X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X509")
.generateCertificate(new ByteArrayInputStream(holder.getEncoded()));
return new CertificateToken(cert);
}
public CertificateToken generateRootCertificateWithCrl(SignatureAlgorithm algorithm, X500Name subject, X500Name issuer, PrivateKey issuerPrivateKey,
PublicKey publicKey, Date notBefore, Date notAfter) throws Exception {
// generate certificate
final SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
final X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(issuer,
new BigInteger("" + new Random().nextInt(10) + System.currentTimeMillis()), notBefore, notAfter, subject, keyInfo);
certBuilder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign));
// Sign the new certificate with the private key of the trusted third
final ContentSigner signer = new JcaContentSignerBuilder(algorithm.getJCEId()).setProvider(BouncyCastleProvider.PROVIDER_NAME).build(issuerPrivateKey);
final X509CertificateHolder holder = certBuilder.build(signer);
final X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X509")
.generateCertificate(new ByteArrayInputStream(holder.getEncoded()));
return new CertificateToken(cert);
}
public CertificateToken generateRootCertificateWithoutCrl(SignatureAlgorithm algorithm, X500Name subject, X500Name issuer, PrivateKey issuerPrivateKey,
PublicKey publicKey, Date notBefore, Date notAfter) throws Exception {
// generate certificate
final SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());
final X509v3CertificateBuilder certBuilder = new X509v3CertificateBuilder(issuer,
new BigInteger("" + new Random().nextInt(10) + System.currentTimeMillis()), notBefore, notAfter, subject, keyInfo);
certBuilder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign));
// Sign the new certificate with the private key of the trusted third
final ContentSigner signer = new JcaContentSignerBuilder(algorithm.getJCEId()).setProvider(BouncyCastleProvider.PROVIDER_NAME).build(issuerPrivateKey);
final X509CertificateHolder holder = certBuilder.build(signer);
final X509Certificate cert = (X509Certificate) CertificateFactory.getInstance("X509")
.generateCertificate(new ByteArrayInputStream(holder.getEncoded()));
return new CertificateToken(cert);
}
private CertificateToken[] createChildCertificateChain(DSSPrivateKeyEntry rootEntry) {
List<CertificateToken> chainList = new ArrayList<CertificateToken>();
chainList.add(rootEntry.getCertificate());
CertificateToken[] rootChain = rootEntry.getCertificateChain();
if ((rootChain != null) && (rootChain.length > 0)) {
for (CertificateToken certChainItem : rootChain) {
chainList.add(certChainItem);
}
}
CertificateToken[] chain = chainList.toArray(new CertificateToken[chainList.size()]);
return chain;
}
}