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()); | |
} | |
} |