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