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