1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45: import ;
46: import ;
47:
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60: import ;
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67:
68: import ;
69:
70:
75: public class X509CRL extends java.security.cert.X509CRL
76: implements GnuPKIExtension
77: {
78:
79:
80:
81:
82: private static final boolean DEBUG = false;
83: private static void debug(String msg)
84: {
85: if (DEBUG)
86: {
87: System.err.print(">> X509CRL: ");
88: System.err.println(msg);
89: }
90: }
91:
92: private static final OID ID_DSA = new OID("1.2.840.10040.4.1");
93: private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3");
94: private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1");
95: private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2");
96: private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4");
97: private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5");
98:
99: private byte[] encoded;
100:
101: private byte[] tbsCRLBytes;
102: private int version;
103: private OID algId;
104: private byte[] algParams;
105: private Date thisUpdate;
106: private Date nextUpdate;
107: private X500DistinguishedName issuerDN;
108: private HashMap revokedCerts;
109: private HashMap extensions;
110:
111: private OID sigAlg;
112: private byte[] sigAlgParams;
113: private byte[] rawSig;
114: private byte[] signature;
115:
116:
117:
118:
119:
126: public X509CRL(InputStream encoded) throws CRLException, IOException
127: {
128: super();
129: revokedCerts = new HashMap();
130: extensions = new HashMap();
131: try
132: {
133: parse(encoded);
134: }
135: catch (IOException ioe)
136: {
137: ioe.printStackTrace();
138: throw ioe;
139: }
140: catch (Exception x)
141: {
142: x.printStackTrace();
143: throw new CRLException(x.toString());
144: }
145: }
146:
147:
148:
149:
150: public boolean equals(Object o)
151: {
152: if (!(o instanceof X509CRL))
153: return false;
154: return ((X509CRL) o).getRevokedCertificates().equals(revokedCerts.values());
155: }
156:
157: public int hashCode()
158: {
159: return revokedCerts.hashCode();
160: }
161:
162: public byte[] getEncoded() throws CRLException
163: {
164: return (byte[]) encoded.clone();
165: }
166:
167: public void verify(PublicKey key)
168: throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
169: NoSuchProviderException, SignatureException
170: {
171: Signature sig = Signature.getInstance(sigAlg.toString());
172: doVerify(sig, key);
173: }
174:
175: public void verify(PublicKey key, String provider)
176: throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
177: NoSuchProviderException, SignatureException
178: {
179: Signature sig = Signature.getInstance(sigAlg.toString(), provider);
180: doVerify(sig, key);
181: }
182:
183: public int getVersion()
184: {
185: return version;
186: }
187:
188: public Principal getIssuerDN()
189: {
190: return issuerDN;
191: }
192:
193: public X500Principal getIssuerX500Principal()
194: {
195: return new X500Principal(issuerDN.getDer());
196: }
197:
198: public Date getThisUpdate()
199: {
200: return (Date) thisUpdate.clone();
201: }
202:
203: public Date getNextUpdate()
204: {
205: if (nextUpdate != null)
206: return (Date) nextUpdate.clone();
207: return null;
208: }
209:
210: public java.security.cert.X509CRLEntry getRevokedCertificate(BigInteger serialNo)
211: {
212: return (java.security.cert.X509CRLEntry) revokedCerts.get(serialNo);
213: }
214:
215: public Set getRevokedCertificates()
216: {
217: return Collections.unmodifiableSet(new HashSet(revokedCerts.values()));
218: }
219:
220: public byte[] getTBSCertList() throws CRLException
221: {
222: return (byte[]) tbsCRLBytes.clone();
223: }
224:
225: public byte[] getSignature()
226: {
227: return (byte[]) rawSig.clone();
228: }
229:
230: public String getSigAlgName()
231: {
232: if (sigAlg.equals(ID_DSA_WITH_SHA1))
233: return "SHA1withDSA";
234: if (sigAlg.equals(ID_RSA_WITH_MD2))
235: return "MD2withRSA";
236: if (sigAlg.equals(ID_RSA_WITH_MD5))
237: return "MD5withRSA";
238: if (sigAlg.equals(ID_RSA_WITH_SHA1))
239: return "SHA1withRSA";
240: return "unknown";
241: }
242:
243: public String getSigAlgOID()
244: {
245: return sigAlg.toString();
246: }
247:
248: public byte[] getSigAlgParams()
249: {
250: if (sigAlgParams != null)
251: return (byte[]) sigAlgParams.clone();
252: return null;
253: }
254:
255:
256:
257:
258: public boolean hasUnsupportedCriticalExtension()
259: {
260: for (Iterator it = extensions.values().iterator(); it.hasNext(); )
261: {
262: Extension e = (Extension) it.next();
263: if (e.isCritical() && !e.isSupported())
264: return true;
265: }
266: return false;
267: }
268:
269: public Set getCriticalExtensionOIDs()
270: {
271: HashSet s = new HashSet();
272: for (Iterator it = extensions.values().iterator(); it.hasNext(); )
273: {
274: Extension e = (Extension) it.next();
275: if (e.isCritical())
276: s.add(e.getOid().toString());
277: }
278: return Collections.unmodifiableSet(s);
279: }
280:
281: public Set getNonCriticalExtensionOIDs()
282: {
283: HashSet s = new HashSet();
284: for (Iterator it = extensions.values().iterator(); it.hasNext(); )
285: {
286: Extension e = (Extension) it.next();
287: if (!e.isCritical())
288: s.add(e.getOid().toString());
289: }
290: return Collections.unmodifiableSet(s);
291: }
292:
293: public byte[] getExtensionValue(String oid)
294: {
295: Extension e = getExtension(new OID(oid));
296: if (e != null)
297: {
298: return e.getValue().getEncoded();
299: }
300: return null;
301: }
302:
303:
304:
305:
306: public Extension getExtension(OID oid)
307: {
308: return (Extension) extensions.get(oid);
309: }
310:
311: public Collection getExtensions()
312: {
313: return extensions.values();
314: }
315:
316:
317:
318:
319: public String toString()
320: {
321: return X509CRL.class.getName();
322: }
323:
324: public boolean isRevoked(Certificate cert)
325: {
326: if (!(cert instanceof java.security.cert.X509Certificate))
327: throw new IllegalArgumentException("not a X.509 certificate");
328: BigInteger certSerial =
329: ((java.security.cert.X509Certificate) cert).getSerialNumber();
330: X509CRLEntry ent = (X509CRLEntry) revokedCerts.get(certSerial);
331: if (ent == null)
332: return false;
333: return ent.getRevocationDate().compareTo(new Date()) < 0;
334: }
335:
336:
337:
338:
339: private void doVerify(Signature sig, PublicKey key)
340: throws CRLException, InvalidKeyException, SignatureException
341: {
342: sig.initVerify(key);
343: sig.update(tbsCRLBytes);
344: if (!sig.verify(signature))
345: throw new CRLException("signature not verified");
346: }
347:
348: private void parse(InputStream in) throws Exception
349: {
350:
351: DERReader der = new DERReader(in);
352: DERValue val = der.read();
353: debug("start CertificateList len == " + val.getLength());
354: if (!val.isConstructed())
355: throw new IOException("malformed CertificateList");
356: encoded = val.getEncoded();
357:
358:
359: val = der.read();
360: if (!val.isConstructed())
361: throw new IOException("malformed TBSCertList");
362: debug("start tbsCertList len == " + val.getLength());
363: tbsCRLBytes = val.getEncoded();
364:
365:
366:
367: val = der.read();
368: if (val.getValue() instanceof BigInteger)
369: {
370: version = ((BigInteger) val.getValue()).intValue() + 1;
371: val = der.read();
372: }
373: else
374: version = 1;
375: debug("read version == " + version);
376:
377:
378: debug("start AlgorithmIdentifier len == " + val.getLength());
379: if (!val.isConstructed())
380: throw new IOException("malformed AlgorithmIdentifier");
381: DERValue algIdVal = der.read();
382: algId = (OID) algIdVal.getValue();
383: debug("read object identifier == " + algId);
384: if (val.getLength() > algIdVal.getEncodedLength())
385: {
386: val = der.read();
387: debug("read parameters len == " + val.getEncodedLength());
388: algParams = val.getEncoded();
389: if (val.isConstructed())
390: in.skip(val.getLength());
391: }
392:
393:
394: val = der.read();
395: issuerDN = new X500DistinguishedName(val.getEncoded());
396: der.skip(val.getLength());
397: debug("read issuer == " + issuerDN);
398:
399:
400: thisUpdate = (Date) der.read().getValue();
401: debug("read thisUpdate == " + thisUpdate);
402:
403:
404: val = der.read();
405: if (val.getValue() instanceof Date)
406: {
407: nextUpdate = (Date) val.getValue();
408: debug("read nextUpdate == " + nextUpdate);
409: val = der.read();
410: }
411:
412:
413:
414:
415: if (val.getTag() != 0)
416: {
417: int len = 0;
418: while (len < val.getLength())
419: {
420: X509CRLEntry entry = new X509CRLEntry(version, der);
421: revokedCerts.put(entry.getSerialNumber(), entry);
422: len += entry.getEncoded().length;
423: }
424: val = der.read();
425: }
426:
427:
428:
429: if (val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0)
430: {
431: if (version < 2)
432: throw new IOException("extra data in CRL");
433: DERValue exts = der.read();
434: if (!exts.isConstructed())
435: throw new IOException("malformed Extensions");
436: debug("start Extensions len == " + exts.getLength());
437: int len = 0;
438: while (len < exts.getLength())
439: {
440: DERValue ext = der.read();
441: if (!ext.isConstructed())
442: throw new IOException("malformed Extension");
443: Extension e = new Extension(ext.getEncoded());
444: extensions.put(e.getOid(), e);
445: der.skip(ext.getLength());
446: len += ext.getEncodedLength();
447: debug("current count == " + len);
448: }
449: val = der.read();
450: }
451:
452: debug("read tag == " + val.getTag());
453: if (!val.isConstructed())
454: throw new IOException("malformed AlgorithmIdentifier");
455: debug("start AlgorithmIdentifier len == " + val.getLength());
456: DERValue sigAlgVal = der.read();
457: debug("read tag == " + sigAlgVal.getTag());
458: if (sigAlgVal.getTag() != DER.OBJECT_IDENTIFIER)
459: throw new IOException("malformed AlgorithmIdentifier");
460: sigAlg = (OID) sigAlgVal.getValue();
461: debug("signature id == " + sigAlg);
462: debug("sigAlgVal length == " + sigAlgVal.getEncodedLength());
463: if (val.getLength() > sigAlgVal.getEncodedLength())
464: {
465: val = der.read();
466: debug("sig params tag = " + val.getTag() + " len == " + val.getEncodedLength());
467: sigAlgParams = (byte[]) val.getEncoded();
468: if (val.isConstructed())
469: in.skip(val.getLength());
470: }
471: val = der.read();
472: debug("read tag = " + val.getTag());
473: rawSig = val.getEncoded();
474: signature = ((BitString) val.getValue()).toByteArray();
475: }
476: }