1 package org.gudy.bouncycastle.jce.provider;
2 
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.math.BigInteger;
6 import java.security.InvalidKeyException;
7 import java.security.NoSuchAlgorithmException;
8 import java.security.NoSuchProviderException;
9 import java.security.Principal;
10 import java.security.Provider;
11 import java.security.PublicKey;
12 import java.security.Security;
13 import java.security.Signature;
14 import java.security.SignatureException;
15 import java.security.cert.CRLException;
16 import java.security.cert.Certificate;
17 import java.security.cert.X509CRL;
18 import java.security.cert.X509CRLEntry;
19 import java.security.cert.X509Certificate;
20 import java.util.Date;
21 import java.util.Enumeration;
22 import java.util.HashSet;
23 import java.util.Set;
24 
25 import javax.security.auth.x500.X500Principal;
26 
27 import org.gudy.bouncycastle.jce.provider.BouncyCastleProvider;
28 import org.gudy.bouncycastle.jce.provider.X509CRLEntryObject;
29 import org.gudy.bouncycastle.asn1.ASN1OutputStream;
30 import org.gudy.bouncycastle.asn1.DERObjectIdentifier;
31 import org.gudy.bouncycastle.asn1.DEROutputStream;
32 import org.gudy.bouncycastle.asn1.x509.CertificateList;
33 import org.gudy.bouncycastle.asn1.x509.TBSCertList;
34 import org.gudy.bouncycastle.asn1.x509.X509Extension;
35 import org.gudy.bouncycastle.asn1.x509.X509Extensions;
36 import org.gudy.bouncycastle.jce.X509Principal;
37 
38 /**
39  * The following extensions are listed in RFC 2459 as relevant to CRLs
40  *
41  * Authority Key Identifier
42  * Issuer Alternative Name
43  * CRL Number
44  * Delta CRL Indicator (critical)
45  * Issuing Distribution Point (critical)
46  */
47 public class X509CRLObject
48     extends X509CRL
49 {
50     private CertificateList c;
51 
X509CRLObject( CertificateList c)52     public X509CRLObject(
53         CertificateList c)
54     {
55         this.c = c;
56     }
57 
58 	/**
59 	 * Will return true if any extensions are present and marked
60 	 * as critical as we currently dont handle any extensions!
61 	 */
hasUnsupportedCriticalExtension()62     public boolean hasUnsupportedCriticalExtension()
63 	{
64 		Set extns = getCriticalExtensionOIDs();
65 		if ( extns != null && !extns.isEmpty() )
66 		{
67 			return true;
68 		}
69 
70 		return false;
71 	}
72 
getExtensionOIDs(boolean critical)73 	private Set getExtensionOIDs(boolean critical)
74 	{
75 		if (this.getVersion() == 2)
76 		{
77 			HashSet         set = new HashSet();
78 			X509Extensions  extensions = c.getTBSCertList().getExtensions();
79 			Enumeration     e = extensions.oids();
80 
81 			while (e.hasMoreElements())
82 			{
83 				DERObjectIdentifier oid = (DERObjectIdentifier)e.nextElement();
84 				X509Extension       ext = extensions.getExtension(oid);
85 
86 				if (critical == ext.isCritical())
87 				{
88 					set.add(oid.getId());
89 				}
90 			}
91 
92 			return set;
93 		}
94 
95 		return null;
96 	}
97 
getCriticalExtensionOIDs()98     public Set getCriticalExtensionOIDs()
99 	{
100 		return getExtensionOIDs(true);
101 	}
102 
getNonCriticalExtensionOIDs()103     public Set getNonCriticalExtensionOIDs()
104 	{
105 		return getExtensionOIDs(false);
106 	}
107 
getExtensionValue(String oid)108     public byte[] getExtensionValue(String oid)
109 	{
110 		X509Extensions exts = c.getTBSCertList().getExtensions();
111 
112 		if (exts != null)
113 		{
114 			X509Extension   ext = exts.getExtension(new DERObjectIdentifier(oid));
115 
116 			if (ext != null)
117 			{
118                 ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
119                 DEROutputStream dOut = new DEROutputStream(bOut);
120 
121                 try
122                 {
123                     dOut.writeObject(ext.getValue());
124 
125                     return bOut.toByteArray();
126                 }
127                 catch (Exception e)
128                 {
129                     throw new RuntimeException("error encoding " + e.toString());
130                 }
131 			}
132 		}
133 
134 		return null;
135 	}
136 
getEncoded()137     public byte[] getEncoded()
138         throws CRLException
139 	{
140 		ByteArrayOutputStream	bOut = new ByteArrayOutputStream();
141 		DEROutputStream			dOut = new DEROutputStream(bOut);
142 
143 		try
144 		{
145 			dOut.writeObject(c);
146 
147 			return bOut.toByteArray();
148 		}
149 		catch (IOException e)
150 		{
151 			throw new CRLException(e.toString());
152 		}
153 	}
154 
verify(PublicKey key)155     public void verify(PublicKey key)
156         throws CRLException,  NoSuchAlgorithmException,
157         InvalidKeyException, NoSuchProviderException,
158         SignatureException
159 	{
160 		verify(key, BouncyCastleProvider.PROVIDER_NAME);
161 	}
162 
verify(PublicKey key, String sigProvider)163     public void verify(PublicKey key, String sigProvider)
164         throws CRLException, NoSuchAlgorithmException,
165         InvalidKeyException, NoSuchProviderException,
166         SignatureException
167 	{
168 		if ( !c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature()) )
169 		{
170 			throw new CRLException("Signature algorithm on CertifcateList does not match TBSCertList.");
171 		}
172 
173 		Signature sig = Signature.getInstance(getSigAlgName(), sigProvider);
174 
175 		sig.initVerify(key);
176 		sig.update(this.getTBSCertList());
177 		if ( !sig.verify(this.getSignature()) )
178 		{
179 			throw new SignatureException("CRL does not verify with supplied public key.");
180 		}
181 	}
182 
getVersion()183     public int getVersion()
184 	{
185 		return c.getVersion();
186 	}
187 
getIssuerDN()188     public Principal getIssuerDN()
189 	{
190 		return new X509Principal(c.getIssuer());
191 	}
192 
getIssuerX500Principal()193     public X500Principal getIssuerX500Principal()
194     {
195         try
196         {
197             ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
198             ASN1OutputStream        aOut = new ASN1OutputStream(bOut);
199 
200             aOut.writeObject(c.getIssuer());
201 
202             return new X500Principal(bOut.toByteArray());
203         }
204         catch (IOException e)
205         {
206             throw new IllegalStateException("can't encode issuer DN");
207         }
208     }
209 
getThisUpdate()210     public Date getThisUpdate()
211 	{
212 		return c.getThisUpdate().getDate();
213 	}
214 
getNextUpdate()215     public Date getNextUpdate()
216 	{
217 		if (c.getNextUpdate() != null)
218 		{
219 			return c.getNextUpdate().getDate();
220 		}
221 
222 		return null;
223 	}
224 
getRevokedCertificate(BigInteger serialNumber)225     public X509CRLEntry getRevokedCertificate(BigInteger serialNumber)
226 	{
227 		TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
228 
229 		if ( certs != null )
230 		{
231 			for ( int i = 0; i < certs.length; i++ )
232 			{
233 				if ( certs[i].getUserCertificate().getValue().equals(serialNumber) ) {
234 					return new X509CRLEntryObject(certs[i]);
235 				}
236 			}
237 		}
238 
239 		return null;
240 	}
241 
getRevokedCertificates()242     public Set getRevokedCertificates()
243 	{
244 		TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
245 
246 		if ( certs != null )
247 		{
248 			HashSet set = new HashSet();
249 			for ( int i = 0; i < certs.length; i++ )
250 			{
251 				set.add(new X509CRLEntryObject(certs[i]));
252 
253 			}
254 
255 			return set;
256 		}
257 
258 		return null;
259 	}
260 
getTBSCertList()261     public byte[] getTBSCertList()
262 		throws CRLException
263 	{
264 		ByteArrayOutputStream	bOut = new ByteArrayOutputStream();
265 		DEROutputStream			dOut = new DEROutputStream(bOut);
266 
267 		try
268 		{
269 			dOut.writeObject(c.getTBSCertList());
270 
271 			return bOut.toByteArray();
272 		}
273 		catch (IOException e)
274 		{
275 			throw new CRLException(e.toString());
276 		}
277 	}
278 
getSignature()279     public byte[] getSignature()
280 	{
281 		return c.getSignature().getBytes();
282 	}
283 
getSigAlgName()284     public String getSigAlgName()
285 	{
286 		Provider	prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);
287 		String		algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
288 
289 		if ( algName != null )
290 		{
291 			return algName;
292 		}
293 
294 		Provider[] provs = Security.getProviders();
295 
296 		//
297 		// search every provider looking for a real algorithm
298 		//
299 		for (int i = 0; i != provs.length; i++)
300 		{
301 			algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID());
302 			if ( algName != null )
303 			{
304 				return algName;
305 			}
306 		}
307 
308 		return this.getSigAlgOID();
309 	}
310 
getSigAlgOID()311     public String getSigAlgOID()
312 	{
313 		return c.getSignatureAlgorithm().getObjectId().getId();
314 	}
315 
getSigAlgParams()316     public byte[] getSigAlgParams()
317 	{
318 		ByteArrayOutputStream	bOut = new ByteArrayOutputStream();
319 
320 		if ( c.getSignatureAlgorithm().getParameters() != null )
321 		{
322 			try
323 			{
324 				DEROutputStream	dOut = new DEROutputStream(bOut);
325 
326 				dOut.writeObject(c.getSignatureAlgorithm().getParameters());
327 			}
328 			catch (Exception e)
329 			{
330 				throw new RuntimeException("exception getting sig parameters " + e);
331 			}
332 
333 			return bOut.toByteArray();
334 		}
335 
336 		return null;
337 	}
338 
339     /**
340      * Returns a string representation of this CRL.
341      *
342      * @return a string representation of this CRL.
343      */
toString()344     public String toString()
345 	{
346 		return "X.509 CRL";
347 	}
348 
349     /**
350      * Checks whether the given certificate is on this CRL.
351      *
352      * @param cert the certificate to check for.
353      * @return true if the given certificate is on this CRL,
354      * false otherwise.
355      */
isRevoked(Certificate cert)356     public boolean isRevoked(Certificate cert)
357 	{
358 		if ( !cert.getType().equals("X.509") )
359 		{
360 			throw new RuntimeException("X.509 CRL used with non X.509 Cert");
361 		}
362 
363 		TBSCertList.CRLEntry[] certs = c.getRevokedCertificates();
364 
365 		if ( certs != null )
366 		{
367 			BigInteger serial = ((X509Certificate)cert).getSerialNumber();
368 
369 			for ( int i = 0; i < certs.length; i++ )
370 			{
371 				if ( certs[i].getUserCertificate().getValue().equals(serial) )
372 				{
373 					return true;
374 				}
375 			}
376 		}
377 
378 		return false;
379 	}
380 }
381 
382