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