1 /* X509CRL.java -- X.509 certificate revocation list.
2    Copyright (C) 2003 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package gnu.java.security.x509;
40 
41 import java.io.InputStream;
42 import java.io.IOException;
43 
44 import java.math.BigInteger;
45 
46 import java.util.Calendar;
47 import java.util.Collections;
48 import java.util.Date;
49 import java.util.HashSet;
50 import java.util.HashMap;
51 import java.util.Set;
52 
53 import java.security.InvalidKeyException;
54 import java.security.NoSuchAlgorithmException;
55 import java.security.NoSuchProviderException;
56 import java.security.PublicKey;
57 import java.security.Principal;
58 import java.security.Signature;
59 import java.security.SignatureException;
60 import java.security.cert.Certificate;
61 import java.security.cert.CRLException;
62 import java.security.cert.X509CRLEntry;
63 
64 import javax.security.auth.x500.X500Principal;
65 
66 import gnu.java.io.ASN1ParsingException;
67 import gnu.java.security.OID;
68 import gnu.java.security.der.BitString;
69 import gnu.java.security.der.DER;
70 import gnu.java.security.der.DERReader;
71 import gnu.java.security.der.DERValue;
72 import gnu.java.security.der.DERWriter;
73 
74 /**
75  * X.509 certificate revocation lists.
76  *
77  * @author Casey Marshall (rsdio@metastatic.org)
78  */
79 public class X509CRL extends java.security.cert.X509CRL
80 {
81 
82   // Constants and fields.
83   // ------------------------------------------------------------------------
84 
85   private static final OID ID_DSA = new OID("1.2.840.10040.4.1");
86   private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3");
87   private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1");
88   private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2");
89   private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4");
90   private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5");
91 
92   private byte[] encoded;
93 
94   private byte[] tbsCRLBytes;
95   private int version;
96   private OID algId;
97   private byte[] algParams;
98   private Date thisUpdate;
99   private Date nextUpdate;
100   private X500Principal issuerDN;
101   private HashMap revokedCerts;
102   private HashMap extensions;
103   private HashSet critOids;
104   private HashSet nonCritOids;
105 
106   private OID sigAlg;
107   private byte[] sigAlgParams;
108   private byte[] rawSig;
109   private byte[] signature;
110 
111   // Constructors.
112   // ------------------------------------------------------------------------
113 
114   /**
115    * Create a new X.509 CRL.
116    *
117    * @param encoded The DER encoded CRL.
118    * @throws CRLException If the input bytes are incorrect.
119    * @throws IOException  If the input bytes cannot be read.
120    */
X509CRL(InputStream encoded)121   public X509CRL(InputStream encoded) throws CRLException, IOException
122   {
123     super();
124     revokedCerts = new HashMap();
125     extensions = new HashMap();
126     critOids = new HashSet();
127     nonCritOids = new HashSet();
128     try
129       {
130         parse(encoded);
131       }
132     catch (IOException ioe)
133       {
134         ioe.printStackTrace();
135         throw ioe;
136       }
137     catch (Exception x)
138       {
139         x.printStackTrace();
140         throw new CRLException(x.toString());
141       }
142   }
143 
144   // X509CRL methods.
145   // ------------------------------------------------------------------------
146 
equals(Object o)147   public boolean equals(Object o)
148   {
149     return ((X509CRL) o).revokedCerts.equals(revokedCerts);
150   }
151 
hashCode()152   public int hashCode()
153   {
154     return revokedCerts.hashCode();
155   }
156 
getEncoded()157   public byte[] getEncoded() throws CRLException
158   {
159     return (byte[]) encoded.clone();
160   }
161 
verify(PublicKey key)162   public void verify(PublicKey key)
163     throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
164            NoSuchProviderException, SignatureException
165   {
166     Signature sig = Signature.getInstance(sigAlg.toString());
167     doVerify(sig, key);
168   }
169 
verify(PublicKey key, String provider)170   public void verify(PublicKey key, String provider)
171     throws CRLException, NoSuchAlgorithmException, InvalidKeyException,
172            NoSuchProviderException, SignatureException
173   {
174     Signature sig = Signature.getInstance(sigAlg.toString(), provider);
175     doVerify(sig, key);
176   }
177 
getVersion()178   public int getVersion()
179   {
180     return version;
181   }
182 
getIssuerDN()183   public Principal getIssuerDN()
184   {
185     return issuerDN;
186   }
187 
getIssuerX500Principal()188   public X500Principal getIssuerX500Principal()
189   {
190     return issuerDN;
191   }
192 
getThisUpdate()193   public Date getThisUpdate()
194   {
195     return (Date) thisUpdate.clone();
196   }
197 
getNextUpdate()198   public Date getNextUpdate()
199   {
200     if (nextUpdate != null)
201       return (Date) nextUpdate.clone();
202     return null;
203   }
204 
getRevokedCertificate(BigInteger serialNo)205   public X509CRLEntry getRevokedCertificate(BigInteger serialNo)
206   {
207     return (X509CRLEntry) revokedCerts.get(serialNo);
208   }
209 
getRevokedCertificates()210   public Set getRevokedCertificates()
211   {
212     return Collections.unmodifiableSet(new HashSet(revokedCerts.values()));
213   }
214 
getTBSCertList()215   public byte[] getTBSCertList() throws CRLException
216   {
217     return (byte[]) tbsCRLBytes.clone();
218   }
219 
getSignature()220   public byte[] getSignature()
221   {
222     return (byte[]) rawSig.clone();
223   }
224 
getSigAlgName()225   public String getSigAlgName()
226   {
227     if (sigAlg.equals(ID_DSA_WITH_SHA1))
228       return "SHA1withDSA";
229     if (sigAlg.equals(ID_RSA_WITH_MD2))
230       return "MD2withRSA";
231     if (sigAlg.equals(ID_RSA_WITH_MD5))
232       return "MD5withRSA";
233     if (sigAlg.equals(ID_RSA_WITH_SHA1))
234       return "SHA1withRSA";
235     return "unknown";
236   }
237 
getSigAlgOID()238   public String getSigAlgOID()
239   {
240     return sigAlg.toString();
241   }
242 
getSigAlgParams()243   public byte[] getSigAlgParams()
244   {
245     if (sigAlgParams != null)
246       return (byte[]) sigAlgParams.clone();
247     return null;
248   }
249 
250   // X509Extension methods.
251   // ------------------------------------------------------------------------
252 
hasUnsupportedCriticalExtension()253   public boolean hasUnsupportedCriticalExtension()
254   {
255     return false; // XXX
256   }
257 
getCriticalExtensionOIDs()258   public Set getCriticalExtensionOIDs()
259   {
260     return Collections.unmodifiableSet(critOids);
261   }
262 
getNonCriticalExtensionOIDs()263   public Set getNonCriticalExtensionOIDs()
264   {
265     return Collections.unmodifiableSet(nonCritOids);
266   }
267 
getExtensionValue(String oid)268   public byte[] getExtensionValue(String oid)
269   {
270     byte[] ext = (byte[]) extensions.get(oid);
271     if (ext != null)
272       return (byte[]) ext.clone();
273     return null;
274   }
275 
276   // CRL methods.
277   // ------------------------------------------------------------------------
278 
toString()279   public String toString()
280   {
281     return gnu.java.security.x509.X509CRL.class.getName();
282   }
283 
isRevoked(Certificate cert)284   public boolean isRevoked(Certificate cert)
285   {
286     if (!(cert instanceof java.security.cert.X509Certificate))
287       throw new IllegalArgumentException("not a X.509 certificate");
288     BigInteger certSerial =
289       ((java.security.cert.X509Certificate) cert).getSerialNumber();
290     X509CRLEntry ent = (X509CRLEntry) revokedCerts.get(certSerial);
291     if (ent == null)
292       return false;
293     return ent.getRevocationDate().compareTo(new Date()) < 0;
294   }
295 
296   // Own methods.
297   // ------------------------------------------------------------------------
298 
doVerify(Signature sig, PublicKey key)299   private void doVerify(Signature sig, PublicKey key)
300     throws CRLException, InvalidKeyException, SignatureException
301   {
302     sig.initVerify(key);
303     sig.update(tbsCRLBytes);
304     if (!sig.verify(signature))
305       throw new CRLException("signature not verified");
306   }
307 
parse(InputStream in)308   private void parse(InputStream in) throws Exception
309   {
310     DERReader der = new DERReader(in);
311     DERValue val = der.read();
312     if (!val.isConstructed())
313       throw new ASN1ParsingException("malformed CertificateList");
314     encoded = val.getEncoded();
315 
316     val = der.read();
317     if (!val.isConstructed())
318       throw new ASN1ParsingException("malformed TBSCertList");
319     tbsCRLBytes = val.getEncoded();
320 
321     val = der.read();
322     if (val.getValue() instanceof BigInteger)
323       {
324         version = ((BigInteger) val.getValue()).intValue() + 1;
325         val = der.read();
326       }
327     else
328       version = 1;
329 
330     if (!val.isConstructed())
331       throw new ASN1ParsingException("malformed AlgorithmIdentifier");
332     DERValue algIdVal = der.read();
333     algId = (OID) algIdVal.getValue();
334     if (val.getLength() > algIdVal.getEncodedLength())
335       {
336         val = der.read();
337         algParams = val.getEncoded();
338         if (val.isConstructed())
339           in.skip(val.getLength());
340       }
341 
342     issuerDN = new X500Principal(in);
343 
344     thisUpdate = (Date) der.read().getValue();
345 
346     val = der.read();
347     if (val.getValue() instanceof Date)
348       {
349         nextUpdate = (Date) val.getValue();
350         val = der.read();
351       }
352     if (val.getTag() != 0)
353       {
354         int len = 0;
355         while (len < val.getLength())
356           {
357             X509CRLEntry entry =
358                new gnu.java.security.x509.X509CRLEntry(version, in);
359             revokedCerts.put(entry.getSerialNumber(), entry);
360             len += entry.getEncoded().length;
361           }
362       }
363     if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0)
364       {
365         val = der.read();
366         int len = 0;
367         while (len < val.getLength())
368           {
369             DERValue ext = der.read();
370             OID extId = (OID) der.read().getValue();
371             DERValue val2 = der.read();
372             Boolean crit = Boolean.valueOf(false);
373             if (val2.getValue() instanceof Boolean)
374               {
375                 crit = (Boolean) val2.getValue();
376                 val2 = der.read();
377               }
378             byte[] extVal = (byte[]) val2.getValue();
379             extensions.put(extId.toString(), extVal);
380             if (crit.booleanValue())
381               critOids.add(extId.toString());
382             else
383               nonCritOids.add(extId.toString());
384             len += ext.getEncodedLength();
385           }
386       }
387 
388     val = der.read();
389     if (!val.isConstructed())
390       throw new ASN1ParsingException("malformed AlgorithmIdentifier");
391     DERValue sigAlgVal = der.read();
392     sigAlg = (OID) sigAlgVal.getValue();
393     if (val.getLength() > sigAlgVal.getEncodedLength())
394       {
395         val = der.read();
396         sigAlgParams = (byte[]) val.getEncoded();
397         if (val.isConstructed())
398           in.skip(val.getLength());
399       }
400     val = der.read();
401     rawSig = val.getEncoded();
402     signature = ((BitString) val.getValue()).toByteArray();
403   }
404 }
405