package org.bouncycastle.jce.provider; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Principal; import java.security.Provider; import java.security.PublicKey; import java.security.Security; import java.security.Signature; import java.security.SignatureException; import java.security.cert.CRLException; import java.security.cert.Certificate; import java.security.cert.X509CRL; import java.security.cert.X509CRLEntry; import java.security.cert.X509Certificate; import java.util.Date; import java.util.Enumeration; import java.util.HashSet; import java.util.Set; import javax.security.auth.x500.X500Principal; import org.bouncycastle.asn1.ASN1OutputStream; import org.bouncycastle.asn1.DERObjectIdentifier; import org.bouncycastle.asn1.DEROutputStream; import org.bouncycastle.asn1.x509.CertificateList; import org.bouncycastle.asn1.x509.TBSCertList; import org.bouncycastle.asn1.x509.X509Extension; import org.bouncycastle.asn1.x509.X509Extensions; import org.bouncycastle.jce.X509Principal; /** * The following extensions are listed in RFC 2459 as relevant to CRLs * * Authority Key Identifier * Issuer Alternative Name * CRL Number * Delta CRL Indicator (critical) * Issuing Distribution Point (critical) */ public class X509CRLObject extends X509CRL { private CertificateList c; public X509CRLObject( CertificateList c) { this.c = c; } /** * Will return true if any extensions are present and marked * as critical as we currently dont handle any extensions! */ public boolean hasUnsupportedCriticalExtension() { Set extns = getCriticalExtensionOIDs(); if ( extns != null && !extns.isEmpty() ) { return true; } return false; } private Set getExtensionOIDs(boolean critical) { if (this.getVersion() == 2) { HashSet set = new HashSet(); X509Extensions extensions = c.getTBSCertList().getExtensions(); Enumeration e = extensions.oids(); while (e.hasMoreElements()) { DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement(); X509Extension ext = extensions.getExtension(oid); if (critical == ext.isCritical()) { set.add(oid.getId()); } } return set; } return null; } public Set getCriticalExtensionOIDs() { return getExtensionOIDs(true); } public Set getNonCriticalExtensionOIDs() { return getExtensionOIDs(false); } public byte[] getExtensionValue(String oid) { X509Extensions exts = c.getTBSCertList().getExtensions(); if (exts != null) { X509Extension ext = exts.getExtension(new DERObjectIdentifier(oid)); if (ext != null) { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); DEROutputStream dOut = new DEROutputStream(bOut); try { dOut.writeObject(ext.getValue()); return bOut.toByteArray(); } catch (Exception e) { throw new RuntimeException("error encoding " + e.toString()); } } } return null; } public byte[] getEncoded() throws CRLException { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); DEROutputStream dOut = new DEROutputStream(bOut); try { dOut.writeObject(c); return bOut.toByteArray(); } catch (IOException e) { throw new CRLException(e.toString()); } } public void verify(PublicKey key) throws CRLException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException { verify(key, BouncyCastleProvider.PROVIDER_NAME); } public void verify(PublicKey key, String sigProvider) throws CRLException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException { if ( !c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()) ) { throw new CRLException("Signature algorithm on CertifcateList does not match TBSCertList."); } Signature sig = Signature.getInstance(getSigAlgName(), sigProvider); sig.initVerify(key); sig.update(this.getTBSCertList()); if ( !sig.verify(this.getSignature()) ) { throw new SignatureException("CRL does not verify with supplied public key."); } } public int getVersion() { return c.getVersion(); } public Principal getIssuerDN() { return new X509Principal(c.getIssuer()); } public X500Principal getIssuerX500Principal() { try { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); ASN1OutputStream aOut = new ASN1OutputStream(bOut); aOut.writeObject(c.getIssuer()); return new X500Principal(bOut.toByteArray()); } catch (IOException e) { throw new IllegalStateException("can't encode issuer DN"); } } public Date getThisUpdate() { return c.getThisUpdate().getDate(); } public Date getNextUpdate() { if (c.getNextUpdate() != null) { return c.getNextUpdate().getDate(); } return null; } public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) { TBSCertList.CRLEntry[] certs = c.getRevokedCertificates(); if ( certs != null ) { for ( int i = 0; i < certs.length; i++ ) { if ( certs[i].getUserCertificate().getValue().equals(serialNumber) ) { return new X509CRLEntryObject(certs[i]); } } } return null; } public Set getRevokedCertificates() { TBSCertList.CRLEntry[] certs = c.getRevokedCertificates(); if ( certs != null ) { HashSet set = new HashSet(); for ( int i = 0; i < certs.length; i++ ) { set.add(new X509CRLEntryObject(certs[i])); } return set; } return null; } public byte[] getTBSCertList() throws CRLException { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); DEROutputStream dOut = new DEROutputStream(bOut); try { dOut.writeObject(c.getTBSCertList()); return bOut.toByteArray(); } catch (IOException e) { throw new CRLException(e.toString()); } } public byte[] getSignature() { return c.getSignature().getBytes(); } public String getSigAlgName() { Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME); String algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID()); if ( algName != null ) { return algName; } Provider[] provs = Security.getProviders(); // // search every provider looking for a real algorithm // for (int i = 0; i != provs.length; i++) { algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID()); if ( algName != null ) { return algName; } } return this.getSigAlgOID(); } public String getSigAlgOID() { return c.getSignatureAlgorithm().getObjectId().getId(); } public byte[] getSigAlgParams() { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); if ( c.getSignatureAlgorithm().getParameters() != null ) { try { DEROutputStream dOut = new DEROutputStream(bOut); dOut.writeObject(c.getSignatureAlgorithm().getParameters()); } catch (Exception e) { throw new RuntimeException("exception getting sig parameters " + e); } return bOut.toByteArray(); } return null; } /** * Returns a string representation of this CRL. * * @return a string representation of this CRL. */ public String toString() { return "X.509 CRL"; } /** * Checks whether the given certificate is on this CRL. * * @param cert the certificate to check for. * @return true if the given certificate is on this CRL, * false otherwise. */ public boolean isRevoked(Certificate cert) { if ( !cert.getType().equals("X.509") ) { throw new RuntimeException("X.509 CRL used with non X.509 Cert"); } TBSCertList.CRLEntry[] certs = c.getRevokedCertificates(); if ( certs != null ) { BigInteger serial = ((X509Certificate)cert).getSerialNumber(); for ( int i = 0; i < certs.length; i++ ) { if ( certs[i].getUserCertificate().getValue().equals(serial) ) { return true; } } } return false; } }