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