• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package org.bouncycastle.cert;
2 
3 import java.io.ByteArrayInputStream;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.OutputStream;
7 import java.math.BigInteger;
8 import java.util.ArrayList;
9 import java.util.Collection;
10 import java.util.Enumeration;
11 import java.util.List;
12 import java.util.Set;
13 
14 import org.bouncycastle.asn1.ASN1InputStream;
15 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
16 import org.bouncycastle.asn1.ASN1Primitive;
17 import org.bouncycastle.asn1.DEROutputStream;
18 import org.bouncycastle.asn1.x500.X500Name;
19 import org.bouncycastle.asn1.x509.CertificateList;
20 import org.bouncycastle.asn1.x509.Extension;
21 import org.bouncycastle.asn1.x509.Extensions;
22 import org.bouncycastle.asn1.x509.GeneralName;
23 import org.bouncycastle.asn1.x509.GeneralNames;
24 import org.bouncycastle.asn1.x509.IssuingDistributionPoint;
25 import org.bouncycastle.asn1.x509.TBSCertList;
26 import org.bouncycastle.operator.ContentVerifier;
27 import org.bouncycastle.operator.ContentVerifierProvider;
28 import org.bouncycastle.util.Encodable;
29 
30 /**
31  * Holding class for an X.509 CRL structure.
32  */
33 public class X509CRLHolder
34     implements Encodable
35 {
36     private CertificateList x509CRL;
37     private boolean isIndirect;
38     private Extensions extensions;
39     private GeneralNames issuerName;
40 
parseStream(InputStream stream)41     private static CertificateList parseStream(InputStream stream)
42         throws IOException
43     {
44         try
45         {
46             ASN1Primitive obj = new ASN1InputStream(stream, true).readObject();
47             if (obj == null)
48             {
49                 throw new IOException("no content found");
50             }
51             return CertificateList.getInstance(obj);
52         }
53         catch (ClassCastException e)
54         {
55             throw new CertIOException("malformed data: " + e.getMessage(), e);
56         }
57         catch (IllegalArgumentException e)
58         {
59             throw new CertIOException("malformed data: " + e.getMessage(), e);
60         }
61     }
62 
isIndirectCRL(Extensions extensions)63     private static boolean isIndirectCRL(Extensions extensions)
64     {
65         if (extensions == null)
66         {
67             return false;
68         }
69 
70         Extension ext = extensions.getExtension(Extension.issuingDistributionPoint);
71 
72         return ext != null && IssuingDistributionPoint.getInstance(ext.getParsedValue()).isIndirectCRL();
73     }
74 
75     /**
76      * Create a X509CRLHolder from the passed in bytes.
77      *
78      * @param crlEncoding BER/DER encoding of the CRL
79      * @throws IOException in the event of corrupted data, or an incorrect structure.
80      */
X509CRLHolder(byte[] crlEncoding)81     public X509CRLHolder(byte[] crlEncoding)
82         throws IOException
83     {
84         this(parseStream(new ByteArrayInputStream(crlEncoding)));
85     }
86 
87     /**
88      * Create a X509CRLHolder from the passed in InputStream.
89      *
90      * @param crlStream BER/DER encoded InputStream of the CRL
91      * @throws IOException in the event of corrupted data, or an incorrect structure.
92      */
X509CRLHolder(InputStream crlStream)93     public X509CRLHolder(InputStream crlStream)
94         throws IOException
95     {
96         this(parseStream(crlStream));
97     }
98 
99     /**
100      * Create a X509CRLHolder from the passed in ASN.1 structure.
101      *
102      * @param x509CRL an ASN.1 CertificateList structure.
103      */
X509CRLHolder(CertificateList x509CRL)104     public X509CRLHolder(CertificateList x509CRL)
105     {
106         this.x509CRL = x509CRL;
107         this.extensions = x509CRL.getTBSCertList().getExtensions();
108         this.isIndirect = isIndirectCRL(extensions);
109         this.issuerName = new GeneralNames(new GeneralName(x509CRL.getIssuer()));
110     }
111 
112     /**
113      * Return the ASN.1 encoding of this holder's CRL.
114      *
115      * @return a DER encoded byte array.
116      * @throws IOException if an encoding cannot be generated.
117      */
getEncoded()118     public byte[] getEncoded()
119         throws IOException
120     {
121         return x509CRL.getEncoded();
122     }
123 
124     /**
125      * Return the issuer of this holder's CRL.
126      *
127      * @return the CRL issuer.
128      */
getIssuer()129     public X500Name getIssuer()
130     {
131         return X500Name.getInstance(x509CRL.getIssuer());
132     }
133 
getRevokedCertificate(BigInteger serialNumber)134     public X509CRLEntryHolder getRevokedCertificate(BigInteger serialNumber)
135     {
136         GeneralNames currentCA = issuerName;
137         for (Enumeration en = x509CRL.getRevokedCertificateEnumeration(); en.hasMoreElements();)
138         {
139             TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)en.nextElement();
140 
141             if (entry.getUserCertificate().getValue().equals(serialNumber))
142             {
143                 return new X509CRLEntryHolder(entry, isIndirect, currentCA);
144             }
145 
146             if (isIndirect && entry.hasExtensions())
147             {
148                 Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer);
149 
150                 if (currentCaName != null)
151                 {
152                     currentCA = GeneralNames.getInstance(currentCaName.getParsedValue());
153                 }
154             }
155         }
156 
157         return null;
158     }
159 
160     /**
161      * Return a collection of X509CRLEntryHolder objects, giving the details of the
162      * revoked certificates that appear on this CRL.
163      *
164      * @return the revoked certificates as a collection of X509CRLEntryHolder objects.
165      */
getRevokedCertificates()166     public Collection getRevokedCertificates()
167     {
168         TBSCertList.CRLEntry[] entries = x509CRL.getRevokedCertificates();
169         List l = new ArrayList(entries.length);
170         GeneralNames currentCA = issuerName;
171 
172         for (Enumeration en = x509CRL.getRevokedCertificateEnumeration(); en.hasMoreElements();)
173         {
174             TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)en.nextElement();
175             X509CRLEntryHolder crlEntry = new X509CRLEntryHolder(entry, isIndirect, currentCA);
176 
177             l.add(crlEntry);
178 
179             currentCA = crlEntry.getCertificateIssuer();
180         }
181 
182         return l;
183     }
184 
185     /**
186      * Return whether or not the holder's CRL contains extensions.
187      *
188      * @return true if extension are present, false otherwise.
189      */
hasExtensions()190     public boolean hasExtensions()
191     {
192         return extensions != null;
193     }
194 
195     /**
196      * Look up the extension associated with the passed in OID.
197      *
198      * @param oid the OID of the extension of interest.
199      *
200      * @return the extension if present, null otherwise.
201      */
getExtension(ASN1ObjectIdentifier oid)202     public Extension getExtension(ASN1ObjectIdentifier oid)
203     {
204         if (extensions != null)
205         {
206             return extensions.getExtension(oid);
207         }
208 
209         return null;
210     }
211 
212     /**
213      * Return the extensions block associated with this CRL if there is one.
214      *
215      * @return the extensions block, null otherwise.
216      */
getExtensions()217     public Extensions getExtensions()
218     {
219         return extensions;
220     }
221 
222     /**
223      * Returns a list of ASN1ObjectIdentifier objects representing the OIDs of the
224      * extensions contained in this holder's CRL.
225      *
226      * @return a list of extension OIDs.
227      */
getExtensionOIDs()228     public List getExtensionOIDs()
229     {
230         return CertUtils.getExtensionOIDs(extensions);
231     }
232 
233     /**
234      * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
235      * critical extensions contained in this holder's CRL.
236      *
237      * @return a set of critical extension OIDs.
238      */
getCriticalExtensionOIDs()239     public Set getCriticalExtensionOIDs()
240     {
241         return CertUtils.getCriticalExtensionOIDs(extensions);
242     }
243 
244     /**
245      * Returns a set of ASN1ObjectIdentifier objects representing the OIDs of the
246      * non-critical extensions contained in this holder's CRL.
247      *
248      * @return a set of non-critical extension OIDs.
249      */
getNonCriticalExtensionOIDs()250     public Set getNonCriticalExtensionOIDs()
251     {
252         return CertUtils.getNonCriticalExtensionOIDs(extensions);
253     }
254 
255     /**
256      * Return the underlying ASN.1 structure for the CRL in this holder.
257      *
258      * @return a CertificateList object.
259      */
toASN1Structure()260     public CertificateList toASN1Structure()
261     {
262         return x509CRL;
263     }
264 
265     /**
266      * Validate the signature on the CRL.
267      *
268      * @param verifierProvider a ContentVerifierProvider that can generate a verifier for the signature.
269      * @return true if the signature is valid, false otherwise.
270      * @throws CertException if the signature cannot be processed or is inappropriate.
271      */
isSignatureValid(ContentVerifierProvider verifierProvider)272     public boolean isSignatureValid(ContentVerifierProvider verifierProvider)
273         throws CertException
274     {
275         TBSCertList tbsCRL = x509CRL.getTBSCertList();
276 
277         if (!CertUtils.isAlgIdEqual(tbsCRL.getSignature(), x509CRL.getSignatureAlgorithm()))
278         {
279             throw new CertException("signature invalid - algorithm identifier mismatch");
280         }
281 
282         ContentVerifier verifier;
283 
284         try
285         {
286             verifier = verifierProvider.get((tbsCRL.getSignature()));
287 
288             OutputStream sOut = verifier.getOutputStream();
289             DEROutputStream dOut = new DEROutputStream(sOut);
290 
291             dOut.writeObject(tbsCRL);
292 
293             sOut.close();
294         }
295         catch (Exception e)
296         {
297             throw new CertException("unable to process signature: " + e.getMessage(), e);
298         }
299 
300         return verifier.verify(x509CRL.getSignature().getOctets());
301     }
302 
equals( Object o)303     public boolean equals(
304         Object o)
305     {
306         if (o == this)
307         {
308             return true;
309         }
310 
311         if (!(o instanceof X509CRLHolder))
312         {
313             return false;
314         }
315 
316         X509CRLHolder other = (X509CRLHolder)o;
317 
318         return this.x509CRL.equals(other.x509CRL);
319     }
320 
hashCode()321     public int hashCode()
322     {
323         return this.x509CRL.hashCode();
324     }
325 }
326