• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
readDERCertificate( ASN1InputStream dIn)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 
getCertificate()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 
readPEMCertificate( InputStream in)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 
createCRL(CertificateList c)106     protected CRL createCRL(CertificateList c)
107     throws CRLException
108     {
109         return new X509CRLObject(c);
110     }
111 
readPEMCRL( InputStream in)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 
readDERCRL( ASN1InputStream aIn)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 
getCRL()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      */
engineGenerateCertificate( InputStream in)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      */
engineGenerateCertificates( InputStream inStream)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      */
engineGenerateCRL( InputStream inStream)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      */
engineGenerateCRLs( InputStream inStream)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 
engineGetCertPathEncodings()333     public Iterator engineGetCertPathEncodings()
334     {
335         return PKIXCertPath.certPathEncodings.iterator();
336     }
337 
engineGenerateCertPath( InputStream inStream)338     public CertPath engineGenerateCertPath(
339         InputStream inStream)
340         throws CertificateException
341     {
342         return engineGenerateCertPath(inStream, "PkiPath");
343     }
344 
engineGenerateCertPath( InputStream inStream, String encoding)345     public CertPath engineGenerateCertPath(
346         InputStream inStream,
347         String encoding)
348         throws CertificateException
349     {
350         return new PKIXCertPath(inStream, encoding);
351     }
352 
engineGenerateCertPath( List certificates)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 
ExCertificateException(Throwable cause)378         public ExCertificateException(Throwable cause)
379         {
380             this.cause = cause;
381         }
382 
ExCertificateException(String msg, Throwable cause)383         public ExCertificateException(String msg, Throwable cause)
384         {
385             super(msg);
386 
387             this.cause = cause;
388         }
389 
getCause()390         public Throwable getCause()
391         {
392             return cause;
393         }
394     }
395 }
396