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.valueOf(0)) <= 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 (NoSuchAlgorithmException e)
359         {
360             throw new SecurityException("exception: " + e);
361         }
362         catch (GeneralSecurityException e)
363         {
364             throw new SecurityException("exception: " + e);
365         }
366     }
367 
368     /**
369      * generate an X509 certificate, based on the current issuer and subject
370      * using the default provider.
371      * <p>
372      * <b>Note:</b> this differs from the deprecated method in that the default provider is
373      * used - not "BC".
374      * </p>
375      */
generate( PrivateKey key)376     public X509Certificate generate(
377         PrivateKey      key)
378         throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
379     {
380         return generate(key, (SecureRandom)null);
381     }
382 
383     /**
384      * generate an X509 certificate, based on the current issuer and subject
385      * using the default provider, and the passed in source of randomness
386      * (if required).
387      * <p>
388      * <b>Note:</b> this differs from the deprecated method in that the default provider is
389      * used - not "BC".
390      * </p>
391      */
generate( PrivateKey key, SecureRandom random)392     public X509Certificate generate(
393         PrivateKey      key,
394         SecureRandom    random)
395         throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
396     {
397         TBSCertificate tbsCert = generateTbsCert();
398         byte[] signature;
399 
400         try
401         {
402             signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
403         }
404         catch (IOException e)
405         {
406             throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
407         }
408 
409         try
410         {
411             return generateJcaObject(tbsCert, signature);
412         }
413         catch (CertificateParsingException e)
414         {
415             throw new ExtCertificateEncodingException("exception producing certificate object", e);
416         }
417     }
418 
419     /**
420      * generate an X509 certificate, based on the current issuer and subject,
421      * using the passed in provider for the signing.
422      */
generate( PrivateKey key, String provider)423     public X509Certificate generate(
424         PrivateKey      key,
425         String          provider)
426         throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
427     {
428         return generate(key, provider, null);
429     }
430 
431     /**
432      * generate an X509 certificate, based on the current issuer and subject,
433      * using the passed in provider for the signing and the supplied source
434      * of randomness, if required.
435      */
generate( PrivateKey key, String provider, SecureRandom random)436     public X509Certificate generate(
437         PrivateKey      key,
438         String          provider,
439         SecureRandom    random)
440         throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
441     {
442         TBSCertificate tbsCert = generateTbsCert();
443         byte[] signature;
444 
445         try
446         {
447             signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
448         }
449         catch (IOException e)
450         {
451             throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
452         }
453 
454         try
455         {
456             return generateJcaObject(tbsCert, signature);
457         }
458         catch (CertificateParsingException e)
459         {
460             throw new ExtCertificateEncodingException("exception producing certificate object", e);
461         }
462     }
463 
generateTbsCert()464     private TBSCertificate generateTbsCert()
465     {
466         if (!extGenerator.isEmpty())
467         {
468             tbsGen.setExtensions(extGenerator.generate());
469         }
470 
471         return tbsGen.generateTBSCertificate();
472     }
473 
generateJcaObject(TBSCertificate tbsCert, byte[] signature)474     private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
475         throws CertificateParsingException
476     {
477         ASN1EncodableVector v = new ASN1EncodableVector();
478 
479         v.add(tbsCert);
480         v.add(sigAlgId);
481         v.add(new DERBitString(signature));
482 
483         return new X509CertificateObject(Certificate.getInstance(new DERSequence(v)));
484     }
485 
486     /**
487      * Return an iterator of the signature names supported by the generator.
488      *
489      * @return an iterator containing recognised names.
490      */
getSignatureAlgNames()491     public Iterator getSignatureAlgNames()
492     {
493         return X509Util.getAlgNames();
494     }
495 }
496