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