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