blob: 91314b1c783c803d702e3f119ec4fd79af3a2dfb [file] [log] [blame]
package org.bouncycastle.cert.test;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathBuilderException;
import java.security.cert.CertPathBuilderResult;
import java.security.cert.CertStore;
import java.security.cert.CertStoreParameters;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CRL;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CRLHolder;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v2CRLBuilder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CRLConverter;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.util.test.SimpleTest;
/**
* BC bug test case.
*/
public class CertPathLoopTest
extends SimpleTest
{
/**
* List of trust anchors
*/
private static Set<TrustAnchor> taSet;
/**
* List of certificates and CRLs
*/
private static List<Object> otherList;
/**
* Asks the user about the configuration he want's to test
*
* @param caA
* @param caB
*/
private static void checkUseDistinctCAs(CA caA, CA caB)
{
//Standard configuration : everything in caA
taSet = new HashSet<TrustAnchor>();
taSet.add(caA.ta);
otherList = new ArrayList<Object>();
otherList.add(caA.acCertCrl);
otherList.add(caA.crl);
//User specified configuration : parts of caB
taSet.add(caB.ta);
otherList.add(caB.acCertCrl);
otherList.add(caB.crl);
}
/**
* Creates a collection cert store
*/
static CertStore getStore(Collection col)
throws InvalidAlgorithmParameterException, NoSuchAlgorithmException
{
CertStoreParameters csp = new CollectionCertStoreParameters(col);
return CertStore.getInstance("Collection", csp);
}
public String getName()
{
return "CertPath Loop Test";
}
public void performTest()
throws Exception
{
//Add the provider
Security.addProvider(new BouncyCastleProvider());
//Generate two Cert authorities
CA caA = new CA();
CA caB = new CA();
//Ask the user the conf he want's to test
checkUseDistinctCAs(caA, caB);
//Let's create a target cert under caA
X509CertSelector target = new X509CertSelector();
target.setCertificate(caA.makeNewCert());
//create control parameters
PKIXBuilderParameters params = new PKIXBuilderParameters(taSet, target);
params.addCertStore(getStore(Collections.singleton(target.getCertificate())));
params.addCertStore(getStore(otherList));
//enable revocation check
params.setRevocationEnabled(true);
//Lets Build the path
try
{
CertPathBuilderResult cpbr = CertPathBuilder.getInstance("PKIX", "BC").build(params);
fail("invalid path build");
}
catch (CertPathBuilderException e)
{
if (!e.getCause().getMessage().equals("CertPath for CRL signer failed to validate."))
{
fail("Exception thrown, but wrong one", e.getCause());
}
}
}
/**
* Class simulating a certification authority
*/
private static class CA
{
/**
* key pair generator
*/
final static KeyPairGenerator kpg;
static
{
try
{
kpg = KeyPairGenerator.getInstance("RSA");
//Key size doesn't matter, smaller == Faster
kpg.initialize(512);
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(e);
}
}
/**
* KeyPair signing certificates
*/
private KeyPair caCertKp;
/**
* KeyPair signing CRLs
*/
private KeyPair caCrlKp;
TrustAnchor ta;
/**
* Subject of this CA
*/
X500Name acSubject;
/**
* Certificate signing certificates
*/
X509Certificate acCertAc;
/**
* Certificate signing CRLs
*/
X509Certificate acCertCrl;
/**
* the CRL
*/
X509CRL crl;
/**
* Signers
*/
private ContentSigner caCrlSigner, caCertSigner;
/**
* Serial number counter
*/
private int counter = 1;
/**
* Constructor
*/
public CA()
throws Exception
{
//Init both keypairs
caCertKp = kpg.generateKeyPair();
caCrlKp = kpg.generateKeyPair();
//subject
acSubject = new X500Name("CN=AC_0");
//validity
GregorianCalendar gc = new GregorianCalendar();
Date notBefore = gc.getTime();
gc.add(GregorianCalendar.DAY_OF_YEAR, 1);
Date notAfter = gc.getTime();
//first signer
caCertSigner = new JcaContentSignerBuilder("SHA1withRSA").build(caCertKp.getPrivate());
//top level : issuer is self
X500Name issuer = acSubject;
//reserved for future use (another test case)
ContentSigner thisAcSigner = caCertSigner;
//reserved for future use (another test case)
//First certificate: Certificate authority (BasicConstraints=true) but not CRLSigner
X509CertificateHolder certH = new X509v3CertificateBuilder(
issuer, BigInteger.valueOf(counter++), notBefore, notAfter, acSubject, getPublicKeyInfo(caCertKp.getPublic()))
.addExtension(Extension.basicConstraints, true, new BasicConstraints(true))
.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign))
.build(thisAcSigner);
//lets convert to X509Certificate
acCertAc = convert(certH);
//and build a trust Anchor
ta = new TrustAnchor(acCertAc, null);
//Second signer
caCrlSigner = new JcaContentSignerBuilder("SHA1withRSA").build(caCrlKp.getPrivate());
//second certificate: CRLSigner but not Certificate authority (BasicConstraints=false)
certH = new X509v3CertificateBuilder(
issuer, BigInteger.valueOf(counter++), notBefore, notAfter, acSubject, getPublicKeyInfo(caCrlKp.getPublic()))
.addExtension(Extension.basicConstraints, false, new BasicConstraints(false))
.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.cRLSign))
.build(thisAcSigner);
//lets convert to X509Certificate
acCertCrl = convert(certH);
//And create the CRL
X509CRLHolder crlH = new X509v2CRLBuilder(acSubject, notBefore).setNextUpdate(notAfter).build(caCrlSigner);
//lets convert to X509CRL
crl = convert(crlH);
}
/**
* Creates a child certificate
*/
public X509Certificate makeNewCert()
throws Exception
{
//private key doesn't matter for the test
PublicKey publicKey = kpg.generateKeyPair().getPublic();
//Validity
GregorianCalendar gc = new GregorianCalendar();
Date notBefore = gc.getTime();
gc.add(GregorianCalendar.DAY_OF_YEAR, 1);
Date notAfter = gc.getTime();
//serial
BigInteger certSerial = BigInteger.valueOf(counter++);
//Distinct name based on the serial
X500Name subject = new X500Name("CN=EU_" + certSerial.toString());
//End user certificate, not allowed to do anything
X509CertificateHolder enUserCertH = new X509v3CertificateBuilder(
acSubject, certSerial, notBefore, notAfter, subject, getPublicKeyInfo(publicKey))
.addExtension(Extension.basicConstraints, false, new BasicConstraints(false))
.addExtension(Extension.keyUsage, true, new KeyUsage(0))
.build(caCertSigner);
//lets convert to X509Certificate
return convert(enUserCertH);
}
/**
* convert to X509Certificate
*/
static X509Certificate convert(X509CertificateHolder h)
throws Exception
{
return new JcaX509CertificateConverter().getCertificate(h);
}
/**
* convert to X509CRL
*/
static X509CRL convert(X509CRLHolder h)
throws Exception
{
return new JcaX509CRLConverter().getCRL(h);
}
/**
* convert to SubjectPublicKeyInfo
*/
static SubjectPublicKeyInfo getPublicKeyInfo(PublicKey k)
throws Exception
{
return SubjectPublicKeyInfo.getInstance(k.getEncoded());
}
}
public static void main(String[] args)
{
runTest(new CertPathLoopTest());
}
}