/**
* Copyright (c) 2009 - 2012 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package org.candlepin.util;
import static org.candlepin.test.MatchesPattern.matchesPattern;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import org.apache.commons.io.FileUtils;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERInteger;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.CRLNumber;
import org.bouncycastle.asn1.x509.CRLReason;
import org.bouncycastle.asn1.x509.X509Extension;
import org.bouncycastle.cert.X509CRLHolder;
import org.bouncycastle.cert.X509v2CRLBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CRLConverter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.provider.X509CRLEntryObject;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLEntry;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
public class X509CRLStreamWriterTest {
private static final BouncyCastleProvider BC = new BouncyCastleProvider();
@Rule
public TemporaryFolder folder = new TemporaryFolder();
@Rule
public ExpectedException thrown = ExpectedException.none();
private X500Name issuer;
private ContentSigner signer;
private KeyPair keyPair;
private File outfile;
private KeyPairGenerator generator;
@Before
public void setUp() throws Exception {
issuer = new X500Name("CN=Test Issuer");
generator = KeyPairGenerator.getInstance("RSA");
generator.initialize(2048);
keyPair = generator.generateKeyPair();
signer = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
.setProvider(BC)
.build(keyPair.getPrivate());
outfile = new File(folder.getRoot(), "new.crl");
Security.addProvider(BC);
}
private X509v2CRLBuilder createCRLBuilder() throws Exception {
X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuer, new Date());
crlBuilder.addExtension(X509Extension.authorityKeyIdentifier, false,
new AuthorityKeyIdentifierStructure(keyPair.getPublic()));
/* With a CRL number of 127, incrementing it should cause the number of bytes in the length
* portion of the TLV to increase by one.*/
crlBuilder.addExtension(X509Extension.cRLNumber, false, new CRLNumber(new BigInteger("127")));
crlBuilder.addCRLEntry(new BigInteger("100"), new Date(), CRLReason.unspecified);
return crlBuilder;
}
private X509CRLHolder createCRL() throws Exception {
X509v2CRLBuilder crlBuilder = createCRLBuilder();
X509CRLHolder holder = crlBuilder.build(signer);
return holder;
}
private File writeCRL(X509CRLHolder crl) throws Exception {
File crlToChange = new File(folder.getRoot(), "test.crl");
FileUtils.writeByteArrayToFile(crlToChange, crl.getEncoded());
return crlToChange;
}
private X509CRL readCRL() throws Exception {
return readCRL(keyPair.getPublic());
}
private X509CRL readCRL(PublicKey signatureKey) throws Exception {
// We could return a X509CRLHolder but that class isn't as fully featured as the built in
// X509CRL.
InputStream changedStream = new BufferedInputStream(new FileInputStream(outfile));
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509CRL changedCrl = (X509CRL) cf.generateCRL(changedStream);
changedCrl.verify(signatureKey, BC.PROVIDER_NAME);
return changedCrl;
}
@Test
public void testHandlesExtensions() throws Exception {
File crlToChange = writeCRL(createCRL());
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
stream.preScan(crlToChange).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
X509CRL changedCrl = readCRL();
Set<BigInteger> discoveredSerials = new HashSet<BigInteger>();
for (X509CRLEntry entry : changedCrl.getRevokedCertificates()) {
discoveredSerials.add(entry.getSerialNumber());
}
Set<BigInteger> expected = new HashSet<BigInteger>();
expected.add(new BigInteger("100"));
assertEquals(expected, discoveredSerials);
}
@Test
public void testAddEntryToActualCRL() throws Exception {
ClassLoader classLoader = this.getClass().getClassLoader();
InputStream crl = classLoader.getResourceAsStream("real-crl.der");
InputStream keyStream = classLoader.getResourceAsStream("real.key");
InputStreamReader keyReader = new InputStreamReader(keyStream);
PEMReader reader = null;
try {
reader = new PEMReader(keyReader);
Object pemObj = reader.readObject();
if (pemObj == null) {
crl.close();
throw new RuntimeException("Reading CA private key failed");
}
if (pemObj instanceof KeyPair) {
keyPair = (KeyPair) pemObj;
}
else {
crl.close();
throw new RuntimeException("Unexepected CA key object: " + pemObj.getClass().getName());
}
}
finally {
reader.close();
}
File outfile = new File(folder.getRoot(), "new.crl");
X509CRLStreamWriter stream = new X509CRLStreamWriter(crl,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
// Add enough items to cause the number of length bytes to change
Set<BigInteger> newSerials = new HashSet<BigInteger>(Arrays.asList(
new BigInteger("2358215310"),
new BigInteger("7231352433"),
new BigInteger("8233181205"),
new BigInteger("1455615868"),
new BigInteger("4323487764"),
new BigInteger("6673256679")
));
for (BigInteger i : newSerials) {
stream.add(i, new Date(), CRLReason.privilegeWithdrawn);
}
// Since we have to walk the stream twice, we need two streams!
stream.preScan(classLoader.getResourceAsStream("real-crl.der")).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
X509CRL changedCrl = readCRL();
Set<BigInteger> discoveredSerials = new HashSet<BigInteger>();
for (X509CRLEntry entry : changedCrl.getRevokedCertificates()) {
discoveredSerials.add(entry.getSerialNumber());
}
assertTrue(discoveredSerials.containsAll(newSerials));
}
@Test
public void testAddEntryToBigCRL() throws Exception {
X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuer, new Date());
crlBuilder.addExtension(X509Extension.authorityKeyIdentifier, false,
new AuthorityKeyIdentifierStructure(keyPair.getPublic()));
/* With a CRL number of 127, incrementing it should cause the number of bytes in the length
* portion of the TLV to increase by one.*/
crlBuilder.addExtension(X509Extension.cRLNumber, false, new CRLNumber(new BigInteger("127")));
BigInteger serial = new BigInteger("741696FE9E30AD27", 16);
Set<BigInteger> expected = new HashSet<BigInteger>();
for (int i = 0; i < 10000; i++) {
serial = serial.add(BigInteger.TEN);
crlBuilder.addCRLEntry(serial, new Date(), CRLReason.privilegeWithdrawn);
expected.add(serial);
}
X509CRLHolder holder = crlBuilder.build(signer);
File crlToChange = writeCRL(holder);
File outfile = new File(folder.getRoot(), "new.crl");
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
// Add enough items to cause the number of length bytes to change
Set<BigInteger> newSerials = new HashSet<BigInteger>(Arrays.asList(
new BigInteger("2358215310"),
new BigInteger("7231352433"),
new BigInteger("8233181205"),
new BigInteger("1455615868"),
new BigInteger("4323487764"),
new BigInteger("6673256679")
));
for (BigInteger i : newSerials) {
stream.add(i, new Date(), CRLReason.privilegeWithdrawn);
expected.add(i);
}
stream.preScan(crlToChange).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
X509CRL changedCrl = readCRL();
Set<BigInteger> discoveredSerials = new HashSet<BigInteger>();
for (X509CRLEntry entry : changedCrl.getRevokedCertificates()) {
discoveredSerials.add(entry.getSerialNumber());
}
assertEquals(expected, discoveredSerials);
}
@Test
public void testAddEntryToCRL() throws Exception {
File crlToChange = writeCRL(createCRL());
File outfile = new File(folder.getRoot(), "new.crl");
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
Set<BigInteger> expected = new HashSet<BigInteger>();
expected.add(new BigInteger("100"));
// Add enough items to cause the number of length bytes to change
Set<BigInteger> newSerials = new HashSet<BigInteger>(Arrays.asList(
new BigInteger("2358215310"),
new BigInteger("7231352433"),
new BigInteger("8233181205"),
new BigInteger("1455615868"),
new BigInteger("4323487764"),
new BigInteger("6673256679")
));
for (BigInteger i : newSerials) {
stream.add(i, new Date(), CRLReason.privilegeWithdrawn);
expected.add(i);
}
stream.preScan(crlToChange).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
X509CRL changedCrl = readCRL();
Set<BigInteger> discoveredSerials = new HashSet<BigInteger>();
for (X509CRLEntry entry : changedCrl.getRevokedCertificates()) {
discoveredSerials.add(entry.getSerialNumber());
}
assertEquals(expected, discoveredSerials);
}
@Test
public void testAddEntryToCRLWithNoExtensions() throws Exception {
X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuer, new Date());
crlBuilder.addCRLEntry(new BigInteger("100"), new Date(), CRLReason.unspecified);
X509CRLHolder holder = crlBuilder.build(signer);
File crlToChange = writeCRL(holder);
File outfile = new File(folder.getRoot(), "new.crl");
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
Set<BigInteger> expected = new HashSet<BigInteger>();
expected.add(new BigInteger("100"));
// Add enough items to cause the number of length bytes to change
Set<BigInteger> newSerials = new HashSet<BigInteger>(Arrays.asList(
new BigInteger("2358215310"),
new BigInteger("7231352433"),
new BigInteger("8233181205"),
new BigInteger("1455615868"),
new BigInteger("4323487764"),
new BigInteger("6673256679")
));
for (BigInteger i : newSerials) {
stream.add(i, new Date(), CRLReason.privilegeWithdrawn);
expected.add(i);
}
stream.preScan(crlToChange).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
X509CRL changedCrl = readCRL();
Set<BigInteger> discoveredSerials = new HashSet<BigInteger>();
for (X509CRLEntry entry : changedCrl.getRevokedCertificates()) {
discoveredSerials.add(entry.getSerialNumber());
}
assertEquals(expected, discoveredSerials);
}
@Test
public void testAddEntryToEmptyCRL() throws Exception {
Date oneHourAgo = new Date(new Date().getTime() - 60L * 60L * 1000L);
Date oneHourHence = new Date(new Date().getTime() + 60L * 60L * 1000L);
X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuer, oneHourAgo);
crlBuilder.addExtension(X509Extension.authorityKeyIdentifier, false,
new AuthorityKeyIdentifierStructure(keyPair.getPublic()));
/* With a CRL number of 127, incrementing it should cause the number of bytes in the length
* portion of the TLV to increase by one.*/
crlBuilder.addExtension(X509Extension.cRLNumber, false, new CRLNumber(new BigInteger("127")));
crlBuilder.setNextUpdate(oneHourHence);
X509CRLHolder holder = crlBuilder.build(signer);
File crlToChange = writeCRL(holder);
File outfile = new File(folder.getRoot(), "new.crl");
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
// Add enough items to cause the number of length bytes to change
Set<BigInteger> newSerials = new HashSet<BigInteger>(Arrays.asList(
new BigInteger("2358215310"),
new BigInteger("7231352433"),
new BigInteger("8233181205"),
new BigInteger("1455615868"),
new BigInteger("4323487764"),
new BigInteger("6673256679")
));
for (BigInteger i : newSerials) {
stream.add(i, new Date(), CRLReason.privilegeWithdrawn);
}
stream.preScan(crlToChange).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
X509CRL changedCrl = readCRL();
Set<BigInteger> discoveredSerials = new HashSet<BigInteger>();
for (X509CRLEntry entry : changedCrl.getRevokedCertificates()) {
discoveredSerials.add(entry.getSerialNumber());
}
X509CRL originalCrl = new JcaX509CRLConverter().setProvider(BC).getCRL(holder);
assertNotNull(changedCrl.getNextUpdate());
long changedCrlUpdateDelta =
changedCrl.getNextUpdate().getTime() - changedCrl.getThisUpdate().getTime();
// We're allowing a tolerance of a few milliseconds to deal with minor timing issues
long deltaTolerance = 3;
long deltaDiff = changedCrlUpdateDelta - (oneHourHence.getTime() - oneHourAgo.getTime());
assertTrue(Math.abs(deltaDiff) <= deltaTolerance);
assertThat(changedCrl.getThisUpdate(), greaterThan(originalCrl.getThisUpdate()));
assertEquals(newSerials, discoveredSerials);
assertEquals(originalCrl.getIssuerX500Principal(), changedCrl.getIssuerX500Principal());
ASN1ObjectIdentifier crlNumberOID = X509Extension.cRLNumber;
byte[] oldCrlNumberBytes = originalCrl.getExtensionValue(crlNumberOID.getId());
byte[] newCrlNumberBytes = changedCrl.getExtensionValue(crlNumberOID.getId());
DEROctetString oldOctet = (DEROctetString) DERTaggedObject.fromByteArray(oldCrlNumberBytes);
DEROctetString newOctet = (DEROctetString) DERTaggedObject.fromByteArray(newCrlNumberBytes);
DERInteger oldNumber = (DERInteger) DERTaggedObject.fromByteArray(oldOctet.getOctets());
DERInteger newNumber = (DERInteger) DERTaggedObject.fromByteArray(newOctet.getOctets());
assertEquals(oldNumber.getValue().add(BigInteger.ONE), newNumber.getValue());
ASN1ObjectIdentifier authorityKeyOID = X509Extension.authorityKeyIdentifier;
byte[] oldAuthorityKeyId = originalCrl.getExtensionValue(authorityKeyOID.getId());
byte[] newAuthorityKeyId = changedCrl.getExtensionValue(authorityKeyOID.getId());
assertArrayEquals(oldAuthorityKeyId, newAuthorityKeyId);
}
@Test
public void testAddEntryToEmptyCRLWithNoExtensions() throws Exception {
X509v2CRLBuilder crlBuilder = new X509v2CRLBuilder(issuer, new Date());
X509CRLHolder holder = crlBuilder.build(signer);
File crlToChange = writeCRL(holder);
File outfile = new File(folder.getRoot(), "new.crl");
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
// Add enough items to cause the number of length bytes to change
Set<BigInteger> newSerials = new HashSet<BigInteger>(Arrays.asList(
new BigInteger("2358215310"),
new BigInteger("7231352433"),
new BigInteger("8233181205"),
new BigInteger("1455615868"),
new BigInteger("4323487764"),
new BigInteger("6673256679")
));
for (BigInteger i : newSerials) {
stream.add(i, new Date(), CRLReason.privilegeWithdrawn);
}
thrown.expect(IllegalStateException.class);
thrown.expectMessage(matchesPattern("v1.*"));
stream.preScan(crlToChange).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
}
@Test
public void testKeySizeChange() throws Exception {
int[] sizes = { 1024, 4096 };
for (int size : sizes) {
X509CRLHolder holder = createCRL();
File crlToChange = writeCRL(holder);
generator.initialize(size);
KeyPair differentKeyPair = generator.generateKeyPair();
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) differentKeyPair.getPrivate(), (RSAPublicKey) differentKeyPair.getPublic());
stream.preScan(crlToChange).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
X509CRL originalCrl = new JcaX509CRLConverter().setProvider(BC).getCRL(holder);
X509CRL changedCrl = readCRL(differentKeyPair.getPublic());
Set<BigInteger> discoveredSerials = new HashSet<BigInteger>();
for (X509CRLEntry entry : changedCrl.getRevokedCertificates()) {
discoveredSerials.add(entry.getSerialNumber());
}
Set<BigInteger> expected = new HashSet<BigInteger>();
expected.add(new BigInteger("100"));
assertEquals(expected, discoveredSerials);
// Since the key changed, the authorityKeyIdentifier must change
byte[] oldAkiBytes = originalCrl.getExtensionValue(X509Extension.authorityKeyIdentifier.getId());
byte[] newAkiBytes = changedCrl.getExtensionValue(X509Extension.authorityKeyIdentifier.getId());
AuthorityKeyIdentifierStructure oldAki = new AuthorityKeyIdentifierStructure(oldAkiBytes);
AuthorityKeyIdentifierStructure newAki = new AuthorityKeyIdentifierStructure(newAkiBytes);
assertArrayEquals(oldAki.getKeyIdentifier(),
new AuthorityKeyIdentifierStructure(keyPair.getPublic()).getKeyIdentifier());
assertArrayEquals(newAki.getKeyIdentifier(),
new AuthorityKeyIdentifierStructure(differentKeyPair.getPublic()).getKeyIdentifier());
}
}
@Test
public void testIncrementsExtensions() throws Exception {
File crlToChange = writeCRL(createCRL());
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
stream.preScan(crlToChange).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
X509CRL changedCrl = readCRL();
byte[] val = changedCrl.getExtensionValue(X509Extension.cRLNumber.getId());
DEROctetString s = (DEROctetString) DERTaggedObject.fromByteArray(val);
DERInteger i = (DERInteger) DERTaggedObject.fromByteArray(s.getOctets());
assertTrue("CRL Number not incremented", i.getValue().compareTo(BigInteger.ONE) > 0);
}
@Test
public void testDeleteEntryFromCRL() throws Exception {
X509v2CRLBuilder crlBuilder = createCRLBuilder();
crlBuilder.addCRLEntry(new BigInteger("101"), new Date(), CRLReason.unspecified);
X509CRLHolder holder = crlBuilder.build(signer);
File crlToChange = writeCRL(holder);
CRLEntryValidator validator = new CRLEntryValidator() {
@Override
public boolean shouldDelete(X509CRLEntryObject entry) {
return entry.getSerialNumber().equals(new BigInteger("101"));
}
};
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
stream.add(new BigInteger("9000"), new Date(), 0);
stream.preScan(crlToChange, validator).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
X509CRL changedCrl = readCRL();
Set<BigInteger> discoveredSerials = new HashSet<BigInteger>();
for (X509CRLEntry entry : changedCrl.getRevokedCertificates()) {
discoveredSerials.add(entry.getSerialNumber());
}
Set<BigInteger> expected = new HashSet<BigInteger>();
expected.add(new BigInteger("100"));
expected.add(new BigInteger("9000"));
assertEquals(expected, discoveredSerials);
}
@Test
public void testModifyUpdatedTime() throws Exception {
X509CRLHolder holder = createCRL();
File crlToChange = writeCRL(holder);
Thread.sleep(1000);
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
stream.preScan(crlToChange).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
X509CRL changedCrl = readCRL();
X509CRL originalCrl = new JcaX509CRLConverter().setProvider(BC).getCRL(holder);
assertTrue("Error: CRL thisUpdate field unmodified", originalCrl.getThisUpdate()
.before(changedCrl.getThisUpdate()));
}
@Test
public void testModifyNextUpdateTime() throws Exception {
Calendar c = Calendar.getInstance();
c.add(Calendar.DATE, 1);
Date nextUpdate = c.getTime();
X509v2CRLBuilder crlBuilder = createCRLBuilder();
crlBuilder.setNextUpdate(nextUpdate);
X509CRLHolder holder = crlBuilder.build(signer);
File crlToChange = writeCRL(holder);
Thread.sleep(1000);
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
stream.preScan(crlToChange).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
X509CRL changedCrl = readCRL();
X509CRL originalCrl = new JcaX509CRLConverter().setProvider(BC).getCRL(holder);
assertTrue("Error: CRL nextUpdate field unmodified",
originalCrl.getNextUpdate().before(changedCrl.getNextUpdate()));
}
@Test
public void testSignatureKeyChange() throws Exception {
KeyPair differentKeyPair = generator.generateKeyPair();
ContentSigner otherSigner = new JcaContentSignerBuilder("SHA256WithRSAEncryption")
.setProvider(BC)
.build(differentKeyPair.getPrivate());
X509v2CRLBuilder crlBuilder = createCRLBuilder();
X509CRLHolder holder = crlBuilder.build(otherSigner);
File crlToChange = writeCRL(holder);
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
stream.preScan(crlToChange).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
// No SignatureException should be thrown
readCRL();
}
@Test
public void testUnlockedThrowsException() throws Exception {
File crlToChange = writeCRL(createCRL());
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
stream.add(new BigInteger("9000"), new Date(), 0);
thrown.expect(IllegalStateException.class);
thrown.expectMessage(
matchesPattern("The instance must be.*locked.*"));
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.preScan(crlToChange);
stream.write(o);
o.close();
}
@Test
public void testUnscannedThrowsException() throws Exception {
File crlToChange = writeCRL(createCRL());
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
stream.add(new BigInteger("9000"), new Date(), 0);
thrown.expect(IllegalStateException.class);
thrown.expectMessage(
matchesPattern("The instance must be.*locked.*"));
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.lock();
stream.write(o);
o.close();
}
@Test
public void testSha1Signature() throws Exception {
X509v2CRLBuilder crlBuilder = createCRLBuilder();
String signingAlg = "SHA1WithRSAEncryption";
ContentSigner sha1Signer = new JcaContentSignerBuilder(signingAlg)
.setProvider(BC)
.build(keyPair.getPrivate());
X509CRLHolder holder = crlBuilder.build(sha1Signer);
File crlToChange = writeCRL(holder);
X509CRLStreamWriter stream = new X509CRLStreamWriter(crlToChange,
(RSAPrivateKey) keyPair.getPrivate(), (RSAPublicKey) keyPair.getPublic());
stream.add(new BigInteger("9000"), new Date(), 0);
stream.preScan(crlToChange).lock();
OutputStream o = new BufferedOutputStream(new FileOutputStream(outfile));
stream.write(o);
o.close();
X509CRL changedCrl = readCRL();
Set<BigInteger> discoveredSerials = new HashSet<BigInteger>();
for (X509CRLEntry entry : changedCrl.getRevokedCertificates()) {
discoveredSerials.add(entry.getSerialNumber());
}
Set<BigInteger> expected = new HashSet<BigInteger>();
expected.add(new BigInteger("100"));
expected.add(new BigInteger("9000"));
assertEquals(expected, discoveredSerials);
}
}