1 package org.gudy.bouncycastle.jce;
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.PrivateKey;
10 import java.security.SecureRandom;
11 import java.security.Signature;
12 import java.security.SignatureException;
13 import java.security.cert.X509CRL;
14 import java.text.SimpleDateFormat;
15 import java.util.Date;
16 import java.util.Hashtable;
17 import java.util.SimpleTimeZone;
18 import java.util.Vector;
19 
20 import org.gudy.bouncycastle.asn1.ASN1EncodableVector;
21 import org.gudy.bouncycastle.asn1.DERBitString;
22 import org.gudy.bouncycastle.asn1.DEREncodable;
23 import org.gudy.bouncycastle.asn1.DERInteger;
24 import org.gudy.bouncycastle.asn1.DERObjectIdentifier;
25 import org.gudy.bouncycastle.asn1.DEROctetString;
26 import org.gudy.bouncycastle.asn1.DEROutputStream;
27 import org.gudy.bouncycastle.asn1.DERSequence;
28 import org.gudy.bouncycastle.asn1.DERUTCTime;
29 import org.gudy.bouncycastle.asn1.x509.AlgorithmIdentifier;
30 import org.gudy.bouncycastle.asn1.x509.CertificateList;
31 import org.gudy.bouncycastle.asn1.x509.TBSCertList;
32 import org.gudy.bouncycastle.asn1.x509.V2TBSCertListGenerator;
33 import org.gudy.bouncycastle.asn1.x509.X509Extension;
34 import org.gudy.bouncycastle.asn1.x509.X509Extensions;
35 import org.gudy.bouncycastle.asn1.x509.X509Name;
36 import org.gudy.bouncycastle.jce.provider.BouncyCastleProvider;
37 import org.gudy.bouncycastle.jce.provider.X509CRLObject;
38 
39 /**
40  * class to produce an X.509 Version 2 CRL.
41  * <p>
42  * <b>Note:</b> This class may be subject to change.
43  */
44 public class X509V2CRLGenerator
45 {
46     private SimpleDateFormat            dateF = new SimpleDateFormat("yyMMddHHmmss");
47     private SimpleTimeZone              tz = new SimpleTimeZone(0, "Z");
48     private V2TBSCertListGenerator      tbsGen;
49     private DERObjectIdentifier         sigOID;
50     private AlgorithmIdentifier         sigAlgId;
51     private String                      signatureAlgorithm;
52     private Hashtable                   extensions = null;
53     private Vector                      extOrdering = null;
54 
55     private static Hashtable            algorithms = new Hashtable();
56 
57     static
58     {
59         algorithms.put("MD2WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
60         algorithms.put("MD2WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.2"));
61         algorithms.put("MD5WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
62         algorithms.put("MD5WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.4"));
63         algorithms.put("SHA1WITHRSAENCRYPTION", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
64         algorithms.put("SHA1WITHRSA", new DERObjectIdentifier("1.2.840.113549.1.1.5"));
65         algorithms.put("RIPEMD160WITHRSAENCRYPTION", new DERObjectIdentifier("1.3.36.3.3.1.2"));
66         algorithms.put("RIPEMD160WITHRSA", new DERObjectIdentifier("1.3.36.3.3.1.2"));
67         algorithms.put("SHA1WITHDSA", new DERObjectIdentifier("1.2.840.10040.4.3"));
68         algorithms.put("DSAWITHSHA1", new DERObjectIdentifier("1.2.840.10040.4.3"));
69         algorithms.put("SHA1WITHECDSA", new DERObjectIdentifier("1.2.840.10045.4.1"));
70         algorithms.put("ECDSAWITHSHA1", new DERObjectIdentifier("1.2.840.10045.4.1"));
71     }
72 
X509V2CRLGenerator()73     public X509V2CRLGenerator()
74     {
75         dateF.setTimeZone(tz);
76 
77         tbsGen = new V2TBSCertListGenerator();
78     }
79 
80     /**
81      * reset the generator
82      */
reset()83     public void reset()
84     {
85         tbsGen = new V2TBSCertListGenerator();
86     }
87 
88 
89     /**
90      * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
91      * certificate.
92      */
setIssuerDN( X509Name issuer)93     public void setIssuerDN(
94         X509Name   issuer)
95     {
96         tbsGen.setIssuer(issuer);
97     }
98 
setThisUpdate( Date date)99     public void setThisUpdate(
100         Date    date)
101     {
102         tbsGen.setThisUpdate(new DERUTCTime(dateF.format(date) + "Z"));
103     }
104 
setNextUpdate( Date date)105     public void setNextUpdate(
106         Date    date)
107     {
108         tbsGen.setNextUpdate(new DERUTCTime(dateF.format(date) + "Z"));
109     }
110 
111     /**
112      * Reason being as indicated by ReasonFlags, i.e. ReasonFlags.KEY_COMPROMISE
113      * or 0 if ReasonFlags are not to be used
114      **/
addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason)115     public void addCRLEntry(BigInteger userCertificate, Date revocationDate, int reason)
116     {
117         tbsGen.addCRLEntry(new DERInteger(userCertificate), new DERUTCTime(dateF.format(revocationDate) + "Z"), reason);
118     }
119 
setSignatureAlgorithm( String signatureAlgorithm)120     public void setSignatureAlgorithm(
121         String  signatureAlgorithm)
122     {
123         this.signatureAlgorithm = signatureAlgorithm;
124 
125         sigOID = (DERObjectIdentifier)algorithms.get(signatureAlgorithm.toUpperCase());
126 
127         if (sigOID == null)
128         {
129             throw new IllegalArgumentException("Unknown signature type requested");
130         }
131 
132         sigAlgId = new AlgorithmIdentifier(this.sigOID, null);
133 
134         tbsGen.setSignature(sigAlgId);
135     }
136 
137     /**
138      * add a given extension field for the standard extensions tag (tag 3)
139      */
addExtension( String OID, boolean critical, DEREncodable value)140     public void addExtension(
141         String          OID,
142         boolean         critical,
143         DEREncodable    value)
144     {
145         this.addExtension(new DERObjectIdentifier(OID), critical, value);
146     }
147 
148     /**
149      * add a given extension field for the standard extensions tag (tag 0)
150      */
addExtension( DERObjectIdentifier OID, boolean critical, DEREncodable value)151     public void addExtension(
152         DERObjectIdentifier OID,
153         boolean             critical,
154         DEREncodable        value)
155     {
156         if (extensions == null)
157         {
158             extensions = new Hashtable();
159             extOrdering = new Vector();
160         }
161 
162         ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
163         DEROutputStream         dOut = new DEROutputStream(bOut);
164 
165         try
166         {
167             dOut.writeObject(value);
168         }
169         catch (IOException e)
170         {
171             throw new IllegalArgumentException("error encoding value: " + e);
172         }
173 
174         this.addExtension(OID, critical, bOut.toByteArray());
175     }
176 
177     /**
178      * add a given extension field for the standard extensions tag (tag 0)
179      */
addExtension( String OID, boolean critical, byte[] value)180     public void addExtension(
181         String          OID,
182         boolean         critical,
183         byte[]          value)
184     {
185         this.addExtension(new DERObjectIdentifier(OID), critical, value);
186     }
187 
188     /**
189      * add a given extension field for the standard extensions tag (tag 0)
190      */
addExtension( DERObjectIdentifier OID, boolean critical, byte[] value)191     public void addExtension(
192         DERObjectIdentifier OID,
193         boolean             critical,
194         byte[]              value)
195     {
196         if (extensions == null)
197         {
198             extensions = new Hashtable();
199             extOrdering = new Vector();
200         }
201 
202         extensions.put(OID, new X509Extension(critical, new DEROctetString(value)));
203         extOrdering.addElement(OID);
204     }
205 
206     /**
207      * generate an X509 CRL, based on the current issuer and subject
208      * using the default provider "BC".
209      */
generateX509CRL( PrivateKey key)210     public X509CRL generateX509CRL(
211         PrivateKey      key)
212         throws SecurityException, SignatureException, InvalidKeyException
213     {
214         try
215         {
216             return generateX509CRL(key, BouncyCastleProvider.PROVIDER_NAME, null);
217         }
218         catch (NoSuchProviderException e)
219         {
220             throw new SecurityException("BC provider not installed!");
221         }
222     }
223 
224     /**
225      * generate an X509 CRL, based on the current issuer and subject
226      * using the default provider "BC" and an user defined SecureRandom object as
227      * source of randomness.
228      */
generateX509CRL( PrivateKey key, SecureRandom random)229     public X509CRL generateX509CRL(
230         PrivateKey      key,
231         SecureRandom    random)
232         throws SecurityException, SignatureException, InvalidKeyException
233     {
234         try
235         {
236             return generateX509CRL(key, BouncyCastleProvider.PROVIDER_NAME, random);
237         }
238         catch (NoSuchProviderException e)
239         {
240             throw new SecurityException("BC provider not installed!");
241         }
242     }
243 
244     /**
245      * generate an X509 certificate, based on the current issuer and subject
246      * using the passed in provider for the signing.
247      */
generateX509CRL( PrivateKey key, String provider)248     public X509CRL generateX509CRL(
249         PrivateKey      key,
250         String          provider)
251         throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
252     {
253         return generateX509CRL(key, provider, null);
254     }
255 
256     /**
257      * generate an X509 CRL, based on the current issuer and subject,
258      * using the passed in provider for the signing.
259      */
generateX509CRL( PrivateKey key, String provider, SecureRandom random)260     public X509CRL generateX509CRL(
261         PrivateKey      key,
262         String          provider,
263         SecureRandom    random)
264         throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
265     {
266         Signature sig = null;
267 
268         try
269         {
270             sig = Signature.getInstance(sigOID.getId(), provider);
271         }
272         catch (NoSuchAlgorithmException ex)
273         {
274             try
275             {
276                 sig = Signature.getInstance(signatureAlgorithm, provider);
277             }
278             catch (NoSuchAlgorithmException e)
279             {
280                 throw new SecurityException("exception creating signature: " + e.toString());
281             }
282         }
283 
284         if (random != null)
285         {
286             sig.initSign(key, random);
287         }
288         else
289         {
290             sig.initSign(key);
291         }
292 
293         if (extensions != null)
294         {
295             tbsGen.setExtensions(new X509Extensions(extOrdering, extensions));
296         }
297 
298         TBSCertList tbsCrl = tbsGen.generateTBSCertList();
299 
300         try
301         {
302             ByteArrayOutputStream   bOut = new ByteArrayOutputStream();
303             DEROutputStream         dOut = new DEROutputStream(bOut);
304 
305             dOut.writeObject(tbsCrl);
306 
307             sig.update(bOut.toByteArray());
308         }
309         catch (Exception e)
310         {
311             throw new SecurityException("exception encoding TBS cert - " + e);
312         }
313 
314         // Construct the CRL
315         ASN1EncodableVector  v = new ASN1EncodableVector();
316 
317         v.add(tbsCrl);
318         v.add(sigAlgId);
319         v.add(new DERBitString(sig.sign()));
320 
321         return new X509CRLObject(new CertificateList(new DERSequence(v)));
322     }
323 }
324