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