1 package org.bouncycastle.x509; 2 3 import java.io.IOException; 4 import java.math.BigInteger; 5 import java.security.GeneralSecurityException; 6 import java.security.InvalidKeyException; 7 import java.security.NoSuchAlgorithmException; 8 import java.security.NoSuchProviderException; 9 import java.security.PrivateKey; 10 import java.security.PublicKey; 11 import java.security.SecureRandom; 12 import java.security.SignatureException; 13 import java.security.cert.CertificateEncodingException; 14 import java.security.cert.CertificateParsingException; 15 import java.security.cert.X509Certificate; 16 import java.util.Date; 17 import java.util.Iterator; 18 19 import org.bouncycastle.asn1.ASN1Encodable; 20 import org.bouncycastle.asn1.ASN1EncodableVector; 21 import org.bouncycastle.asn1.ASN1InputStream; 22 import org.bouncycastle.asn1.ASN1Integer; 23 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 24 import org.bouncycastle.asn1.DERBitString; 25 import org.bouncycastle.asn1.ASN1ObjectIdentifier; 26 import org.bouncycastle.asn1.DERSequence; 27 import org.bouncycastle.asn1.x509.AlgorithmIdentifier; 28 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; 29 import org.bouncycastle.asn1.x509.TBSCertificate; 30 import org.bouncycastle.asn1.x509.Time; 31 import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; 32 import org.bouncycastle.asn1.x509.Certificate; 33 import org.bouncycastle.asn1.x509.X509ExtensionsGenerator; 34 import org.bouncycastle.asn1.x509.X509Name; 35 import org.bouncycastle.jce.provider.X509CertificateObject; 36 import org.bouncycastle.x509.extension.X509ExtensionUtil; 37 38 /** 39 * class to produce an X.509 Version 3 certificate. 40 * @deprecated use org.bouncycastle.cert.X509v3CertificateBuilder. 41 */ 42 public class X509V3CertificateGenerator 43 { 44 private V3TBSCertificateGenerator tbsGen; 45 private ASN1ObjectIdentifier sigOID; 46 private AlgorithmIdentifier sigAlgId; 47 private String signatureAlgorithm; 48 private X509ExtensionsGenerator extGenerator; 49 X509V3CertificateGenerator()50 public X509V3CertificateGenerator() 51 { 52 tbsGen = new V3TBSCertificateGenerator(); 53 extGenerator = new X509ExtensionsGenerator(); 54 } 55 56 /** 57 * reset the generator 58 */ reset()59 public void reset() 60 { 61 tbsGen = new V3TBSCertificateGenerator(); 62 extGenerator.reset(); 63 } 64 65 /** 66 * set the serial number for the certificate. 67 */ setSerialNumber( BigInteger serialNumber)68 public void setSerialNumber( 69 BigInteger serialNumber) 70 { 71 if (serialNumber.compareTo(BigInteger.ZERO) <= 0) 72 { 73 throw new IllegalArgumentException("serial number must be a positive integer"); 74 } 75 76 tbsGen.setSerialNumber(new ASN1Integer(serialNumber)); 77 } 78 79 /** 80 * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the 81 * certificate. 82 */ setIssuerDN( X509Name issuer)83 public void setIssuerDN( 84 X509Name issuer) 85 { 86 tbsGen.setIssuer(issuer); 87 } 88 setNotBefore( Date date)89 public void setNotBefore( 90 Date date) 91 { 92 tbsGen.setStartDate(new Time(date)); 93 } 94 setNotAfter( Date date)95 public void setNotAfter( 96 Date date) 97 { 98 tbsGen.setEndDate(new Time(date)); 99 } 100 101 /** 102 * Set the subject distinguished name. The subject describes the entity associated with the public key. 103 */ setSubjectDN( X509Name subject)104 public void setSubjectDN( 105 X509Name subject) 106 { 107 tbsGen.setSubject(subject); 108 } 109 setPublicKey( PublicKey key)110 public void setPublicKey( 111 PublicKey key) 112 throws IllegalArgumentException 113 { 114 try 115 { 116 tbsGen.setSubjectPublicKeyInfo( 117 SubjectPublicKeyInfo.getInstance(new ASN1InputStream(key.getEncoded()).readObject())); 118 } 119 catch (Exception e) 120 { 121 throw new IllegalArgumentException("unable to process key - " + e.toString()); 122 } 123 } 124 125 /** 126 * Set the signature algorithm. This can be either a name or an OID, names 127 * are treated as case insensitive. 128 * 129 * @param signatureAlgorithm string representation of the algorithm name. 130 */ setSignatureAlgorithm( String signatureAlgorithm)131 public void setSignatureAlgorithm( 132 String signatureAlgorithm) 133 { 134 this.signatureAlgorithm = signatureAlgorithm; 135 136 try 137 { 138 sigOID = X509Util.getAlgorithmOID(signatureAlgorithm); 139 } 140 catch (Exception e) 141 { 142 throw new IllegalArgumentException("Unknown signature type requested: " + signatureAlgorithm); 143 } 144 145 sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm); 146 147 tbsGen.setSignature(sigAlgId); 148 } 149 150 /** 151 * Set the subject unique ID - note: it is very rare that it is correct to do this. 152 */ setSubjectUniqueID(boolean[] uniqueID)153 public void setSubjectUniqueID(boolean[] uniqueID) 154 { 155 tbsGen.setSubjectUniqueID(booleanToBitString(uniqueID)); 156 } 157 158 /** 159 * Set the issuer unique ID - note: it is very rare that it is correct to do this. 160 */ setIssuerUniqueID(boolean[] uniqueID)161 public void setIssuerUniqueID(boolean[] uniqueID) 162 { 163 tbsGen.setIssuerUniqueID(booleanToBitString(uniqueID)); 164 } 165 booleanToBitString(boolean[] id)166 private DERBitString booleanToBitString(boolean[] id) 167 { 168 byte[] bytes = new byte[(id.length + 7) / 8]; 169 170 for (int i = 0; i != id.length; i++) 171 { 172 bytes[i / 8] |= (id[i]) ? (1 << ((7 - (i % 8)))) : 0; 173 } 174 175 int pad = id.length % 8; 176 177 if (pad == 0) 178 { 179 return new DERBitString(bytes); 180 } 181 else 182 { 183 return new DERBitString(bytes, 8 - pad); 184 } 185 } 186 187 /** 188 * add a given extension field for the standard extensions tag (tag 3) 189 */ addExtension( String oid, boolean critical, ASN1Encodable value)190 public void addExtension( 191 String oid, 192 boolean critical, 193 ASN1Encodable value) 194 { 195 this.addExtension(new ASN1ObjectIdentifier(oid), critical, value); 196 } 197 198 /** 199 * add a given extension field for the standard extensions tag (tag 3) 200 */ addExtension( ASN1ObjectIdentifier oid, boolean critical, ASN1Encodable value)201 public void addExtension( 202 ASN1ObjectIdentifier oid, 203 boolean critical, 204 ASN1Encodable value) 205 { 206 extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); 207 } 208 209 /** 210 * add a given extension field for the standard extensions tag (tag 3) 211 * The value parameter becomes the contents of the octet string associated 212 * with the extension. 213 */ addExtension( String oid, boolean critical, byte[] value)214 public void addExtension( 215 String oid, 216 boolean critical, 217 byte[] value) 218 { 219 this.addExtension(new ASN1ObjectIdentifier(oid), critical, value); 220 } 221 222 /** 223 * add a given extension field for the standard extensions tag (tag 3) 224 */ addExtension( ASN1ObjectIdentifier oid, boolean critical, byte[] value)225 public void addExtension( 226 ASN1ObjectIdentifier oid, 227 boolean critical, 228 byte[] value) 229 { 230 extGenerator.addExtension(new ASN1ObjectIdentifier(oid.getId()), critical, value); 231 } 232 233 /** 234 * add a given extension field for the standard extensions tag (tag 3) 235 * copying the extension value from another certificate. 236 * @throws CertificateParsingException if the extension cannot be extracted. 237 */ copyAndAddExtension( String oid, boolean critical, X509Certificate cert)238 public void copyAndAddExtension( 239 String oid, 240 boolean critical, 241 X509Certificate cert) 242 throws CertificateParsingException 243 { 244 byte[] extValue = cert.getExtensionValue(oid); 245 246 if (extValue == null) 247 { 248 throw new CertificateParsingException("extension " + oid + " not present"); 249 } 250 251 try 252 { 253 ASN1Encodable value = X509ExtensionUtil.fromExtensionValue(extValue); 254 255 this.addExtension(oid, critical, value); 256 } 257 catch (IOException e) 258 { 259 throw new CertificateParsingException(e.toString()); 260 } 261 } 262 263 /** 264 * add a given extension field for the standard extensions tag (tag 3) 265 * copying the extension value from another certificate. 266 * @throws CertificateParsingException if the extension cannot be extracted. 267 */ copyAndAddExtension( ASN1ObjectIdentifier oid, boolean critical, X509Certificate cert)268 public void copyAndAddExtension( 269 ASN1ObjectIdentifier oid, 270 boolean critical, 271 X509Certificate cert) 272 throws CertificateParsingException 273 { 274 this.copyAndAddExtension(oid.getId(), critical, cert); 275 } 276 277 /** 278 * generate an X509 certificate, based on the current issuer and subject 279 * using the default provider "BC". 280 * @deprecated use generate(key, "BC") 281 */ generateX509Certificate( PrivateKey key)282 public X509Certificate generateX509Certificate( 283 PrivateKey key) 284 throws SecurityException, SignatureException, InvalidKeyException 285 { 286 try 287 { 288 return generateX509Certificate(key, "BC", null); 289 } 290 catch (NoSuchProviderException e) 291 { 292 throw new SecurityException("BC provider not installed!"); 293 } 294 } 295 296 /** 297 * generate an X509 certificate, based on the current issuer and subject 298 * using the default provider "BC", and the passed in source of randomness 299 * (if required). 300 * @deprecated use generate(key, random, "BC") 301 */ generateX509Certificate( PrivateKey key, SecureRandom random)302 public X509Certificate generateX509Certificate( 303 PrivateKey key, 304 SecureRandom random) 305 throws SecurityException, SignatureException, InvalidKeyException 306 { 307 try 308 { 309 return generateX509Certificate(key, "BC", random); 310 } 311 catch (NoSuchProviderException e) 312 { 313 throw new SecurityException("BC provider not installed!"); 314 } 315 } 316 317 /** 318 * generate an X509 certificate, based on the current issuer and subject, 319 * using the passed in provider for the signing. 320 * @deprecated use generate() 321 */ generateX509Certificate( PrivateKey key, String provider)322 public X509Certificate generateX509Certificate( 323 PrivateKey key, 324 String provider) 325 throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException 326 { 327 return generateX509Certificate(key, provider, null); 328 } 329 330 /** 331 * generate an X509 certificate, based on the current issuer and subject, 332 * using the passed in provider for the signing and the supplied source 333 * of randomness, if required. 334 * @deprecated use generate() 335 */ generateX509Certificate( PrivateKey key, String provider, SecureRandom random)336 public X509Certificate generateX509Certificate( 337 PrivateKey key, 338 String provider, 339 SecureRandom random) 340 throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException 341 { 342 try 343 { 344 return generate(key, provider, random); 345 } 346 catch (NoSuchProviderException e) 347 { 348 throw e; 349 } 350 catch (SignatureException e) 351 { 352 throw e; 353 } 354 catch (InvalidKeyException e) 355 { 356 throw e; 357 } 358 catch (GeneralSecurityException e) 359 { 360 throw new SecurityException("exception: " + e); 361 } 362 } 363 364 /** 365 * generate an X509 certificate, based on the current issuer and subject 366 * using the default provider. 367 * <p> 368 * <b>Note:</b> this differs from the deprecated method in that the default provider is 369 * used - not "BC". 370 * </p> 371 */ generate( PrivateKey key)372 public X509Certificate generate( 373 PrivateKey key) 374 throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException 375 { 376 return generate(key, (SecureRandom)null); 377 } 378 379 /** 380 * generate an X509 certificate, based on the current issuer and subject 381 * using the default provider, and the passed in source of randomness 382 * (if required). 383 * <p> 384 * <b>Note:</b> this differs from the deprecated method in that the default provider is 385 * used - not "BC". 386 * </p> 387 */ generate( PrivateKey key, SecureRandom random)388 public X509Certificate generate( 389 PrivateKey key, 390 SecureRandom random) 391 throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException 392 { 393 TBSCertificate tbsCert = generateTbsCert(); 394 byte[] signature; 395 396 try 397 { 398 signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert); 399 } 400 catch (IOException e) 401 { 402 throw new ExtCertificateEncodingException("exception encoding TBS cert", e); 403 } 404 405 try 406 { 407 return generateJcaObject(tbsCert, signature); 408 } 409 catch (CertificateParsingException e) 410 { 411 throw new ExtCertificateEncodingException("exception producing certificate object", e); 412 } 413 } 414 415 /** 416 * generate an X509 certificate, based on the current issuer and subject, 417 * using the passed in provider for the signing. 418 */ generate( PrivateKey key, String provider)419 public X509Certificate generate( 420 PrivateKey key, 421 String provider) 422 throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException 423 { 424 return generate(key, provider, null); 425 } 426 427 /** 428 * generate an X509 certificate, based on the current issuer and subject, 429 * using the passed in provider for the signing and the supplied source 430 * of randomness, if required. 431 */ generate( PrivateKey key, String provider, SecureRandom random)432 public X509Certificate generate( 433 PrivateKey key, 434 String provider, 435 SecureRandom random) 436 throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException 437 { 438 TBSCertificate tbsCert = generateTbsCert(); 439 byte[] signature; 440 441 try 442 { 443 signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert); 444 } 445 catch (IOException e) 446 { 447 throw new ExtCertificateEncodingException("exception encoding TBS cert", e); 448 } 449 450 try 451 { 452 return generateJcaObject(tbsCert, signature); 453 } 454 catch (CertificateParsingException e) 455 { 456 throw new ExtCertificateEncodingException("exception producing certificate object", e); 457 } 458 } 459 generateTbsCert()460 private TBSCertificate generateTbsCert() 461 { 462 if (!extGenerator.isEmpty()) 463 { 464 tbsGen.setExtensions(extGenerator.generate()); 465 } 466 467 return tbsGen.generateTBSCertificate(); 468 } 469 generateJcaObject(TBSCertificate tbsCert, byte[] signature)470 private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature) 471 throws CertificateParsingException 472 { 473 ASN1EncodableVector v = new ASN1EncodableVector(); 474 475 v.add(tbsCert); 476 v.add(sigAlgId); 477 v.add(new DERBitString(signature)); 478 479 return new X509CertificateObject(Certificate.getInstance(new DERSequence(v))); 480 } 481 482 /** 483 * Return an iterator of the signature names supported by the generator. 484 * 485 * @return an iterator containing recognised names. 486 */ getSignatureAlgNames()487 public Iterator getSignatureAlgNames() 488 { 489 return X509Util.getAlgNames(); 490 } 491 } 492