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