Home | History | Annotate | Download | only in x509
      1 package org.bouncycastle.jcajce.provider.asymmetric.x509;
      2 
      3 import java.io.IOException;
      4 import java.io.InputStream;
      5 import java.io.PushbackInputStream;
      6 import java.security.cert.CRL;
      7 import java.security.cert.CRLException;
      8 import java.security.cert.CertPath;
      9 import java.security.cert.CertificateException;
     10 import java.security.cert.CertificateFactorySpi;
     11 import java.security.cert.CertificateParsingException;
     12 import java.security.cert.X509Certificate;
     13 import java.util.ArrayList;
     14 import java.util.Collection;
     15 import java.util.Iterator;
     16 import java.util.List;
     17 
     18 import org.bouncycastle.asn1.ASN1InputStream;
     19 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
     20 import org.bouncycastle.asn1.ASN1Sequence;
     21 import org.bouncycastle.asn1.ASN1Set;
     22 import org.bouncycastle.asn1.ASN1TaggedObject;
     23 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
     24 import org.bouncycastle.asn1.pkcs.SignedData;
     25 import org.bouncycastle.asn1.x509.Certificate;
     26 import org.bouncycastle.asn1.x509.CertificateList;
     27 
     28 /**
     29  * class for dealing with X509 certificates.
     30  * <p>
     31  * At the moment this will deal with "-----BEGIN CERTIFICATE-----" to "-----END CERTIFICATE-----"
     32  * base 64 encoded certs, as well as the BER binaries of certificates and some classes of PKCS#7
     33  * objects.
     34  */
     35 public class CertificateFactory
     36     extends CertificateFactorySpi
     37 {
     38     private static final PEMUtil PEM_CERT_PARSER = new PEMUtil("CERTIFICATE");
     39     private static final PEMUtil PEM_CRL_PARSER = new PEMUtil("CRL");
     40 
     41     private ASN1Set sData = null;
     42     private int                sDataObjectCount = 0;
     43     private InputStream currentStream = null;
     44 
     45     private ASN1Set sCrlData = null;
     46     private int                sCrlDataObjectCount = 0;
     47     private InputStream currentCrlStream = null;
     48 
     49     private java.security.cert.Certificate readDERCertificate(
     50         ASN1InputStream dIn)
     51         throws IOException, CertificateParsingException
     52     {
     53         ASN1Sequence seq = (ASN1Sequence)dIn.readObject();
     54 
     55         if (seq.size() > 1
     56                 && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
     57         {
     58             if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
     59             {
     60                 sData = SignedData.getInstance(ASN1Sequence.getInstance(
     61                     (ASN1TaggedObject)seq.getObjectAt(1), true)).getCertificates();
     62 
     63                 return getCertificate();
     64             }
     65         }
     66 
     67         return new X509CertificateObject(
     68                             Certificate.getInstance(seq));
     69     }
     70 
     71     private java.security.cert.Certificate getCertificate()
     72         throws CertificateParsingException
     73     {
     74         if (sData != null)
     75         {
     76             while (sDataObjectCount < sData.size())
     77             {
     78                 Object obj = sData.getObjectAt(sDataObjectCount++);
     79 
     80                 if (obj instanceof ASN1Sequence)
     81                 {
     82                    return new X509CertificateObject(
     83                                     Certificate.getInstance(obj));
     84                 }
     85             }
     86         }
     87 
     88         return null;
     89     }
     90 
     91     private java.security.cert.Certificate readPEMCertificate(
     92         InputStream in)
     93         throws IOException, CertificateParsingException
     94     {
     95         ASN1Sequence seq = PEM_CERT_PARSER.readPEMObject(in);
     96 
     97         if (seq != null)
     98         {
     99             return new X509CertificateObject(
    100                             Certificate.getInstance(seq));
    101         }
    102 
    103         return null;
    104     }
    105 
    106     protected CRL createCRL(CertificateList c)
    107     throws CRLException
    108     {
    109         return new X509CRLObject(c);
    110     }
    111 
    112     private CRL readPEMCRL(
    113         InputStream in)
    114         throws IOException, CRLException
    115     {
    116         ASN1Sequence seq = PEM_CRL_PARSER.readPEMObject(in);
    117 
    118         if (seq != null)
    119         {
    120             return createCRL(
    121                             CertificateList.getInstance(seq));
    122         }
    123 
    124         return null;
    125     }
    126 
    127     private CRL readDERCRL(
    128         ASN1InputStream aIn)
    129         throws IOException, CRLException
    130     {
    131         ASN1Sequence seq = (ASN1Sequence)aIn.readObject();
    132 
    133         if (seq.size() > 1
    134                 && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier)
    135         {
    136             if (seq.getObjectAt(0).equals(PKCSObjectIdentifiers.signedData))
    137             {
    138                 sCrlData = SignedData.getInstance(ASN1Sequence.getInstance(
    139                     (ASN1TaggedObject)seq.getObjectAt(1), true)).getCRLs();
    140 
    141                 return getCRL();
    142             }
    143         }
    144 
    145         return createCRL(
    146                      CertificateList.getInstance(seq));
    147     }
    148 
    149     private CRL getCRL()
    150         throws CRLException
    151     {
    152         if (sCrlData == null || sCrlDataObjectCount >= sCrlData.size())
    153         {
    154             return null;
    155         }
    156 
    157         return createCRL(
    158                             CertificateList.getInstance(
    159                                 sCrlData.getObjectAt(sCrlDataObjectCount++)));
    160     }
    161 
    162     /**
    163      * Generates a certificate object and initializes it with the data
    164      * read from the input stream inStream.
    165      */
    166     public java.security.cert.Certificate engineGenerateCertificate(
    167         InputStream in)
    168         throws CertificateException
    169     {
    170         if (currentStream == null)
    171         {
    172             currentStream = in;
    173             sData = null;
    174             sDataObjectCount = 0;
    175         }
    176         else if (currentStream != in) // reset if input stream has changed
    177         {
    178             currentStream = in;
    179             sData = null;
    180             sDataObjectCount = 0;
    181         }
    182 
    183         try
    184         {
    185             if (sData != null)
    186             {
    187                 if (sDataObjectCount != sData.size())
    188                 {
    189                     return getCertificate();
    190                 }
    191                 else
    192                 {
    193                     sData = null;
    194                     sDataObjectCount = 0;
    195                     return null;
    196                 }
    197             }
    198 
    199             PushbackInputStream pis = new PushbackInputStream(in);
    200             int tag = pis.read();
    201 
    202             if (tag == -1)
    203             {
    204                 return null;
    205             }
    206 
    207             pis.unread(tag);
    208 
    209             if (tag != 0x30)  // assume ascii PEM encoded.
    210             {
    211                 return readPEMCertificate(pis);
    212             }
    213             else
    214             {
    215                 return readDERCertificate(new ASN1InputStream(pis));
    216             }
    217         }
    218         catch (Exception e)
    219         {
    220             throw new ExCertificateException(e);
    221         }
    222     }
    223 
    224     /**
    225      * Returns a (possibly empty) collection view of the certificates
    226      * read from the given input stream inStream.
    227      */
    228     public Collection engineGenerateCertificates(
    229         InputStream inStream)
    230         throws CertificateException
    231     {
    232         java.security.cert.Certificate     cert;
    233         List certs = new ArrayList();
    234 
    235         while ((cert = engineGenerateCertificate(inStream)) != null)
    236         {
    237             certs.add(cert);
    238         }
    239 
    240         return certs;
    241     }
    242 
    243     /**
    244      * Generates a certificate revocation list (CRL) object and initializes
    245      * it with the data read from the input stream inStream.
    246      */
    247     public CRL engineGenerateCRL(
    248         InputStream inStream)
    249         throws CRLException
    250     {
    251         if (currentCrlStream == null)
    252         {
    253             currentCrlStream = inStream;
    254             sCrlData = null;
    255             sCrlDataObjectCount = 0;
    256         }
    257         else if (currentCrlStream != inStream) // reset if input stream has changed
    258         {
    259             currentCrlStream = inStream;
    260             sCrlData = null;
    261             sCrlDataObjectCount = 0;
    262         }
    263 
    264         try
    265         {
    266             if (sCrlData != null)
    267             {
    268                 if (sCrlDataObjectCount != sCrlData.size())
    269                 {
    270                     return getCRL();
    271                 }
    272                 else
    273                 {
    274                     sCrlData = null;
    275                     sCrlDataObjectCount = 0;
    276                     return null;
    277                 }
    278             }
    279 
    280             PushbackInputStream pis = new PushbackInputStream(inStream);
    281             int tag = pis.read();
    282 
    283             if (tag == -1)
    284             {
    285                 return null;
    286             }
    287 
    288             pis.unread(tag);
    289 
    290             if (tag != 0x30)  // assume ascii PEM encoded.
    291             {
    292                 return readPEMCRL(pis);
    293             }
    294             else
    295             {       // lazy evaluate to help processing of large CRLs
    296                 return readDERCRL(new ASN1InputStream(pis, true));
    297             }
    298         }
    299         catch (CRLException e)
    300         {
    301             throw e;
    302         }
    303         catch (Exception e)
    304         {
    305             throw new CRLException(e.toString());
    306         }
    307     }
    308 
    309     /**
    310      * Returns a (possibly empty) collection view of the CRLs read from
    311      * the given input stream inStream.
    312      *
    313      * The inStream may contain a sequence of DER-encoded CRLs, or
    314      * a PKCS#7 CRL set.  This is a PKCS#7 SignedData object, with the
    315      * only signficant field being crls.  In particular the signature
    316      * and the contents are ignored.
    317      */
    318     public Collection engineGenerateCRLs(
    319         InputStream inStream)
    320         throws CRLException
    321     {
    322         CRL crl;
    323         List crls = new ArrayList();
    324 
    325         while ((crl = engineGenerateCRL(inStream)) != null)
    326         {
    327             crls.add(crl);
    328         }
    329 
    330         return crls;
    331     }
    332 
    333     public Iterator engineGetCertPathEncodings()
    334     {
    335         return PKIXCertPath.certPathEncodings.iterator();
    336     }
    337 
    338     public CertPath engineGenerateCertPath(
    339         InputStream inStream)
    340         throws CertificateException
    341     {
    342         return engineGenerateCertPath(inStream, "PkiPath");
    343     }
    344 
    345     public CertPath engineGenerateCertPath(
    346         InputStream inStream,
    347         String encoding)
    348         throws CertificateException
    349     {
    350         return new PKIXCertPath(inStream, encoding);
    351     }
    352 
    353     public CertPath engineGenerateCertPath(
    354         List certificates)
    355         throws CertificateException
    356     {
    357         Iterator iter = certificates.iterator();
    358         Object obj;
    359         while (iter.hasNext())
    360         {
    361             obj = iter.next();
    362             if (obj != null)
    363             {
    364                 if (!(obj instanceof X509Certificate))
    365                 {
    366                     throw new CertificateException("list contains non X509Certificate object while creating CertPath\n" + obj.toString());
    367                 }
    368             }
    369         }
    370         return new PKIXCertPath(certificates);
    371     }
    372 
    373     private class ExCertificateException
    374         extends CertificateException
    375     {
    376         private Throwable cause;
    377 
    378         public ExCertificateException(Throwable cause)
    379         {
    380             this.cause = cause;
    381         }
    382 
    383         public ExCertificateException(String msg, Throwable cause)
    384         {
    385             super(msg);
    386 
    387             this.cause = cause;
    388         }
    389 
    390         public Throwable getCause()
    391         {
    392             return cause;
    393         }
    394     }
    395 }
    396