Home | History | Annotate | Download | only in provider
      1 package org.bouncycastle.jce.provider;
      2 
      3 import java.io.IOException;
      4 import java.math.BigInteger;
      5 import java.security.InvalidKeyException;
      6 import java.security.NoSuchAlgorithmException;
      7 import java.security.NoSuchProviderException;
      8 import java.security.Principal;
      9 import java.security.Provider;
     10 import java.security.PublicKey;
     11 import java.security.Signature;
     12 import java.security.SignatureException;
     13 import java.security.cert.CRLException;
     14 import java.security.cert.Certificate;
     15 import java.security.cert.CertificateEncodingException;
     16 import java.security.cert.X509CRL;
     17 import java.security.cert.X509CRLEntry;
     18 import java.security.cert.X509Certificate;
     19 import java.util.Collections;
     20 import java.util.Date;
     21 import java.util.Enumeration;
     22 import java.util.HashSet;
     23 import java.util.Iterator;
     24 import java.util.Set;
     25 
     26 import javax.security.auth.x500.X500Principal;
     27 
     28 import org.bouncycastle.asn1.ASN1Encodable;
     29 import org.bouncycastle.asn1.ASN1Encoding;
     30 import org.bouncycastle.asn1.ASN1InputStream;
     31 import org.bouncycastle.asn1.ASN1Integer;
     32 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
     33 import org.bouncycastle.asn1.ASN1OctetString;
     34 import org.bouncycastle.asn1.util.ASN1Dump;
     35 import org.bouncycastle.asn1.x500.X500Name;
     36 import org.bouncycastle.asn1.x509.CRLDistPoint;
     37 import org.bouncycastle.asn1.x509.CRLNumber;
     38 import org.bouncycastle.asn1.x509.CertificateList;
     39 import org.bouncycastle.asn1.x509.Extension;
     40 import org.bouncycastle.asn1.x509.Extensions;
     41 import org.bouncycastle.asn1.x509.GeneralNames;
     42 import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
     43 import org.bouncycastle.asn1.x509.TBSCertList;
     44 import org.bouncycastle.jce.X509Principal;
     45 import org.bouncycastle.util.Strings;
     46 import org.bouncycastle.util.encoders.Hex;
     47 
     48 /**
     49  * The following extensions are listed in RFC 2459 as relevant to CRLs
     50  *
     51  * Authority Key Identifier
     52  * Issuer Alternative Name
     53  * CRL Number
     54  * Delta CRL Indicator (critical)
     55  * Issuing Distribution Point (critical)
     56  * @deprecated Do not use this class directly - either use org.bouncycastle.cert (bcpkix) or CertificateFactory.
     57  */
     58 public class X509CRLObject
     59     extends X509CRL
     60 {
     61     private CertificateList c;
     62     private String sigAlgName;
     63     private byte[] sigAlgParams;
     64     private boolean isIndirect;
     65     private boolean isHashCodeSet = false;
     66     private int     hashCodeValue;
     67 
     68     public static boolean isIndirectCRL(X509CRL crl)
     69         throws CRLException
     70     {
     71         try
     72         {
     73             byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId());
     74             return idp != null
     75                 && IssuingDistributionPoint.getInstance(ASN1OctetString.getInstance(idp).getOctets()).isIndirectCRL();
     76         }
     77         catch (Exception e)
     78         {
     79             throw new ExtCRLException(
     80                     "Exception reading IssuingDistributionPoint", e);
     81         }
     82     }
     83 
     84     public X509CRLObject(
     85         CertificateList c)
     86         throws CRLException
     87     {
     88         this.c = c;
     89 
     90         try
     91         {
     92             this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm());
     93 
     94             if (c.getSignatureAlgorithm().getParameters() != null)
     95             {
     96                 this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER);
     97             }
     98             else
     99             {
    100                 this.sigAlgParams = null;
    101             }
    102 
    103             this.isIndirect = isIndirectCRL(this);
    104         }
    105         catch (Exception e)
    106         {
    107             throw new CRLException("CRL contents invalid: " + e);
    108         }
    109     }
    110 
    111     /**
    112      * Will return true if any extensions are present and marked
    113      * as critical as we currently dont handle any extensions!
    114      */
    115     public boolean hasUnsupportedCriticalExtension()
    116     {
    117         Set extns = getCriticalExtensionOIDs();
    118 
    119         if (extns == null)
    120         {
    121             return false;
    122         }
    123 
    124         extns.remove(RFC3280CertPathUtilities.ISSUING_DISTRIBUTION_POINT);
    125         extns.remove(RFC3280CertPathUtilities.DELTA_CRL_INDICATOR);
    126 
    127         return !extns.isEmpty();
    128     }
    129 
    130     private Set getExtensionOIDs(boolean critical)
    131     {
    132         if (this.getVersion() == 2)
    133         {
    134             Extensions extensions = c.getTBSCertList().getExtensions();
    135 
    136             if (extensions != null)
    137             {
    138                 Set set = new HashSet();
    139                 Enumeration e = extensions.oids();
    140 
    141                 while (e.hasMoreElements())
    142                 {
    143                     ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
    144                     Extension ext = extensions.getExtension(oid);
    145 
    146                     if (critical == ext.isCritical())
    147                     {
    148                         set.add(oid.getId());
    149                     }
    150                 }
    151 
    152                 return set;
    153             }
    154         }
    155 
    156         return null;
    157     }
    158 
    159     public Set getCriticalExtensionOIDs()
    160     {
    161         return getExtensionOIDs(true);
    162     }
    163 
    164     public Set getNonCriticalExtensionOIDs()
    165     {
    166         return getExtensionOIDs(false);
    167     }
    168 
    169     public byte[] getExtensionValue(String oid)
    170     {
    171         Extensions exts = c.getTBSCertList().getExtensions();
    172 
    173         if (exts != null)
    174         {
    175             Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid));
    176 
    177             if (ext != null)
    178             {
    179                 try
    180                 {
    181                     return ext.getExtnValue().getEncoded();
    182                 }
    183                 catch (Exception e)
    184                 {
    185                     throw new IllegalStateException("error parsing " + e.toString());
    186                 }
    187             }
    188         }
    189 
    190         return null;
    191     }
    192 
    193     public byte[] getEncoded()
    194         throws CRLException
    195     {
    196         try
    197         {
    198             return c.getEncoded(ASN1Encoding.DER);
    199         }
    200         catch (IOException e)
    201         {
    202             throw new CRLException(e.toString());
    203         }
    204     }
    205 
    206     public void verify(PublicKey key)
    207         throws CRLException, NoSuchAlgorithmException,
    208         InvalidKeyException, NoSuchProviderException, SignatureException
    209     {
    210         Signature sig;
    211 
    212         try
    213         {
    214             sig = Signature.getInstance(getSigAlgName(), BouncyCastleProvider.PROVIDER_NAME);
    215         }
    216         catch (Exception e)
    217         {
    218             sig = Signature.getInstance(getSigAlgName());
    219         }
    220 
    221         doVerify(key, sig);
    222     }
    223 
    224     public void verify(PublicKey key, String sigProvider)
    225         throws CRLException, NoSuchAlgorithmException,
    226         InvalidKeyException, NoSuchProviderException, SignatureException
    227     {
    228         Signature sig;
    229 
    230         if (sigProvider != null)
    231         {
    232             sig = Signature.getInstance(getSigAlgName(), sigProvider);
    233         }
    234         else
    235         {
    236             sig = Signature.getInstance(getSigAlgName());
    237         }
    238 
    239         doVerify(key, sig);
    240     }
    241 
    242     public void verify(PublicKey key, Provider sigProvider)
    243         throws CRLException, NoSuchAlgorithmException,
    244         InvalidKeyException, SignatureException
    245     {
    246         Signature sig;
    247 
    248         if (sigProvider != null)
    249         {
    250             sig = Signature.getInstance(getSigAlgName(), sigProvider);
    251         }
    252         else
    253         {
    254             sig = Signature.getInstance(getSigAlgName());
    255         }
    256 
    257         doVerify(key, sig);
    258     }
    259 
    260     private void doVerify(PublicKey key, Signature sig)
    261         throws CRLException, NoSuchAlgorithmException,
    262         InvalidKeyException, SignatureException
    263     {
    264         if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()))
    265         {
    266             throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList.");
    267         }
    268 
    269         sig.initVerify(key);
    270         sig.update(this.getTBSCertList());
    271 
    272         if (!sig.verify(this.getSignature()))
    273         {
    274             throw new SignatureException("CRL does not verify with supplied public key.");
    275         }
    276     }
    277 
    278     public int getVersion()
    279     {
    280         return c.getVersionNumber();
    281     }
    282 
    283     public Principal getIssuerDN()
    284     {
    285         return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive()));
    286     }
    287 
    288     public X500Principal getIssuerX500Principal()
    289     {
    290         try
    291         {
    292             return new X500Principal(c.getIssuer().getEncoded());
    293         }
    294         catch (IOException e)
    295         {
    296             throw new IllegalStateException("can't encode issuer DN");
    297         }
    298     }
    299 
    300     public Date getThisUpdate()
    301     {
    302         return c.getThisUpdate().getDate();
    303     }
    304 
    305     public Date getNextUpdate()
    306     {
    307         if (c.getNextUpdate() != null)
    308         {
    309             return c.getNextUpdate().getDate();
    310         }
    311 
    312         return null;
    313     }
    314 
    315     private Set loadCRLEntries()
    316     {
    317         Set entrySet = new HashSet();
    318         Enumeration certs = c.getRevokedCertificateEnumeration();
    319 
    320         X500Name previousCertificateIssuer = null; // the issuer
    321         while (certs.hasMoreElements())
    322         {
    323             TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
    324             X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
    325             entrySet.add(crlEntry);
    326             if (isIndirect && entry.hasExtensions())
    327             {
    328                 Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
    329 
    330                 if (currentCaName != null)
    331                 {
    332                     previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
    333                 }
    334             }
    335         }
    336 
    337         return entrySet;
    338     }
    339 
    340     public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
    341     {
    342         Enumeration certs = c.getRevokedCertificateEnumeration();
    343 
    344         X500Name previousCertificateIssuer = null; // the issuer
    345         while (certs.hasMoreElements())
    346         {
    347             TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement();
    348 
    349             if (serialNumber.equals(entry.getUserCertificate().getValue()))
    350             {
    351                 return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer);
    352             }
    353 
    354             if (isIndirect && entry.hasExtensions())
    355             {
    356                 Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
    357 
    358                 if (currentCaName != null)
    359                 {
    360                     previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
    361                 }
    362             }
    363         }
    364 
    365         return null;
    366     }
    367 
    368     public Set getRevokedCertificates()
    369     {
    370         Set entrySet = loadCRLEntries();
    371 
    372         if (!entrySet.isEmpty())
    373         {
    374             return Collections.unmodifiableSet(entrySet);
    375         }
    376 
    377         return null;
    378     }
    379 
    380     public byte[] getTBSCertList()
    381         throws CRLException
    382     {
    383         try
    384         {
    385             return c.getTBSCertList().getEncoded("DER");
    386         }
    387         catch (IOException e)
    388         {
    389             throw new CRLException(e.toString());
    390         }
    391     }
    392 
    393     public byte[] getSignature()
    394     {
    395         return c.getSignature().getOctets();
    396     }
    397 
    398     public String getSigAlgName()
    399     {
    400         return sigAlgName;
    401     }
    402 
    403     public String getSigAlgOID()
    404     {
    405         return c.getSignatureAlgorithm().getAlgorithm().getId();
    406     }
    407 
    408     public byte[] getSigAlgParams()
    409     {
    410         if (sigAlgParams != null)
    411         {
    412             byte[] tmp = new byte[sigAlgParams.length];
    413 
    414             System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length);
    415 
    416             return tmp;
    417         }
    418 
    419         return null;
    420     }
    421 
    422     /**
    423      * Returns a string representation of this CRL.
    424      *
    425      * @return a string representation of this CRL.
    426      */
    427     public String toString()
    428     {
    429         StringBuffer buf = new StringBuffer();
    430         String nl = Strings.lineSeparator();
    431 
    432         buf.append("              Version: ").append(this.getVersion()).append(
    433             nl);
    434         buf.append("             IssuerDN: ").append(this.getIssuerDN())
    435             .append(nl);
    436         buf.append("          This update: ").append(this.getThisUpdate())
    437             .append(nl);
    438         buf.append("          Next update: ").append(this.getNextUpdate())
    439             .append(nl);
    440         buf.append("  Signature Algorithm: ").append(this.getSigAlgName())
    441             .append(nl);
    442 
    443         byte[] sig = this.getSignature();
    444 
    445         buf.append("            Signature: ").append(
    446             new String(Hex.encode(sig, 0, 20))).append(nl);
    447         for (int i = 20; i < sig.length; i += 20)
    448         {
    449             if (i < sig.length - 20)
    450             {
    451                 buf.append("                       ").append(
    452                     new String(Hex.encode(sig, i, 20))).append(nl);
    453             }
    454             else
    455             {
    456                 buf.append("                       ").append(
    457                     new String(Hex.encode(sig, i, sig.length - i))).append(nl);
    458             }
    459         }
    460 
    461         Extensions extensions = c.getTBSCertList().getExtensions();
    462 
    463         if (extensions != null)
    464         {
    465             Enumeration e = extensions.oids();
    466 
    467             if (e.hasMoreElements())
    468             {
    469                 buf.append("           Extensions: ").append(nl);
    470             }
    471 
    472             while (e.hasMoreElements())
    473             {
    474                 ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement();
    475                 Extension ext = extensions.getExtension(oid);
    476 
    477                 if (ext.getExtnValue() != null)
    478                 {
    479                     byte[] octs = ext.getExtnValue().getOctets();
    480                     ASN1InputStream dIn = new ASN1InputStream(octs);
    481                     buf.append("                       critical(").append(
    482                         ext.isCritical()).append(") ");
    483                     try
    484                     {
    485                         if (oid.equals(Extension.cRLNumber))
    486                         {
    487                             buf.append(
    488                                 new CRLNumber(ASN1Integer.getInstance(
    489                                     dIn.readObject()).getPositiveValue()))
    490                                 .append(nl);
    491                         }
    492                         else if (oid.equals(Extension.deltaCRLIndicator))
    493                         {
    494                             buf.append(
    495                                 "Base CRL: "
    496                                     + new CRLNumber(ASN1Integer.getInstance(
    497                                         dIn.readObject()).getPositiveValue()))
    498                                 .append(nl);
    499                         }
    500                         else if (oid
    501                             .equals(Extension.issuingDistributionPoint))
    502                         {
    503                             buf.append(
    504                                IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl);
    505                         }
    506                         else if (oid
    507                             .equals(Extension.cRLDistributionPoints))
    508                         {
    509                             buf.append(
    510                                 CRLDistPoint.getInstance(dIn.readObject())).append(nl);
    511                         }
    512                         else if (oid.equals(Extension.freshestCRL))
    513                         {
    514                             buf.append(
    515                                 CRLDistPoint.getInstance(dIn.readObject())).append(nl);
    516                         }
    517                         else
    518                         {
    519                             buf.append(oid.getId());
    520                             buf.append(" value = ").append(
    521                                 ASN1Dump.dumpAsString(dIn.readObject()))
    522                                 .append(nl);
    523                         }
    524                     }
    525                     catch (Exception ex)
    526                     {
    527                         buf.append(oid.getId());
    528                         buf.append(" value = ").append("*****").append(nl);
    529                     }
    530                 }
    531                 else
    532                 {
    533                     buf.append(nl);
    534                 }
    535             }
    536         }
    537         Set set = getRevokedCertificates();
    538         if (set != null)
    539         {
    540             Iterator it = set.iterator();
    541             while (it.hasNext())
    542             {
    543                 buf.append(it.next());
    544                 buf.append(nl);
    545             }
    546         }
    547         return buf.toString();
    548     }
    549 
    550     /**
    551      * Checks whether the given certificate is on this CRL.
    552      *
    553      * @param cert the certificate to check for.
    554      * @return true if the given certificate is on this CRL,
    555      * false otherwise.
    556      */
    557     public boolean isRevoked(Certificate cert)
    558     {
    559         if (!cert.getType().equals("X.509"))
    560         {
    561             throw new RuntimeException("X.509 CRL used with non X.509 Cert");
    562         }
    563 
    564         Enumeration certs = c.getRevokedCertificateEnumeration();
    565 
    566         X500Name caName = c.getIssuer();
    567 
    568         if (certs != null)
    569         {
    570             BigInteger serial = ((X509Certificate)cert).getSerialNumber();
    571 
    572             while (certs.hasMoreElements())
    573             {
    574                 TBSCertList.CRLEntry entry = TBSCertList.CRLEntry.getInstance(certs.nextElement());
    575 
    576                 if (isIndirect && entry.hasExtensions())
    577                 {
    578                     Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
    579 
    580                     if (currentCaName != null)
    581                     {
    582                         caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName());
    583                     }
    584                 }
    585 
    586                 if (entry.getUserCertificate().getValue().equals(serial))
    587                 {
    588                     X500Name issuer;
    589 
    590                     if (cert instanceof  X509Certificate)
    591                     {
    592                         issuer = X500Name.getInstance(((X509Certificate)cert).getIssuerX500Principal().getEncoded());
    593                     }
    594                     else
    595                     {
    596                         try
    597                         {
    598                             issuer = org.bouncycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer();
    599                         }
    600                         catch (CertificateEncodingException e)
    601                         {
    602                             throw new RuntimeException("Cannot process certificate");
    603                         }
    604                     }
    605 
    606                     if (!caName.equals(issuer))
    607                     {
    608                         return false;
    609                     }
    610 
    611                     return true;
    612                 }
    613             }
    614         }
    615 
    616         return false;
    617     }
    618 
    619     public boolean equals(Object other)
    620     {
    621         if (this == other)
    622         {
    623             return true;
    624         }
    625 
    626         if (!(other instanceof X509CRL))
    627         {
    628             return false;
    629         }
    630 
    631         if (other instanceof X509CRLObject)
    632         {
    633             X509CRLObject crlObject = (X509CRLObject)other;
    634 
    635             if (isHashCodeSet)
    636             {
    637                 boolean otherIsHashCodeSet = crlObject.isHashCodeSet;
    638                 if (otherIsHashCodeSet)
    639                 {
    640                     if (crlObject.hashCodeValue != hashCodeValue)
    641                     {
    642                         return false;
    643                     }
    644                 }
    645             }
    646 
    647             return this.c.equals(crlObject.c);
    648         }
    649 
    650         return super.equals(other);
    651     }
    652 
    653     public int hashCode()
    654     {
    655         if (!isHashCodeSet)
    656         {
    657             isHashCodeSet = true;
    658             hashCodeValue = super.hashCode();
    659         }
    660 
    661         return hashCodeValue;
    662     }
    663 }
    664 
    665