1package org.bouncycastle.x509;
2
3import java.io.ByteArrayInputStream;
4import java.io.IOException;
5import java.math.BigInteger;
6import java.security.GeneralSecurityException;
7import java.security.InvalidKeyException;
8import java.security.NoSuchAlgorithmException;
9import java.security.NoSuchProviderException;
10import java.security.PrivateKey;
11import java.security.PublicKey;
12import java.security.SecureRandom;
13import java.security.SignatureException;
14import java.security.cert.CertificateEncodingException;
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.ASN1EncodableVector;
22import org.bouncycastle.asn1.ASN1Encoding;
23import org.bouncycastle.asn1.ASN1Integer;
24import org.bouncycastle.asn1.ASN1ObjectIdentifier;
25import org.bouncycastle.asn1.DERBitString;
26import org.bouncycastle.asn1.DERSequence;
27import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
28import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
29import org.bouncycastle.asn1.x509.TBSCertificate;
30import org.bouncycastle.asn1.x509.Time;
31import org.bouncycastle.asn1.x509.V1TBSCertificateGenerator;
32import org.bouncycastle.asn1.x509.X509Name;
33import org.bouncycastle.jcajce.provider.asymmetric.x509.CertificateFactory;
34import org.bouncycastle.jcajce.util.BCJcaJceHelper;
35import org.bouncycastle.jcajce.util.JcaJceHelper;
36import org.bouncycastle.jce.X509Principal;
37
38/**
39 * class to produce an X.509 Version 1 certificate.
40 * @deprecated use org.bouncycastle.cert.X509v1CertificateBuilder.
41 */
42public class X509V1CertificateGenerator
43{
44    private final JcaJceHelper bcHelper = new BCJcaJceHelper(); // needed to force provider loading
45    private final CertificateFactory certificateFactory = new CertificateFactory();
46
47    private V1TBSCertificateGenerator   tbsGen;
48    private ASN1ObjectIdentifier         sigOID;
49    private AlgorithmIdentifier         sigAlgId;
50    private String                      signatureAlgorithm;
51
52    public X509V1CertificateGenerator()
53    {
54        tbsGen = new V1TBSCertificateGenerator();
55    }
56
57    /**
58     * reset the generator
59     */
60    public void reset()
61    {
62        tbsGen = new V1TBSCertificateGenerator();
63    }
64
65    /**
66     * set the serial number for the certificate.
67     */
68    public void setSerialNumber(
69        BigInteger      serialNumber)
70    {
71        if (serialNumber.compareTo(BigInteger.ZERO) <= 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     */
83    public void setIssuerDN(
84        X500Principal   issuer)
85    {
86        try
87        {
88            tbsGen.setIssuer(new X509Principal(issuer.getEncoded()));
89        }
90        catch (IOException e)
91        {
92            throw new IllegalArgumentException("can't process principal: " + e);
93        }
94    }
95
96    /**
97     * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
98     * certificate.
99     */
100    public void setIssuerDN(
101        X509Name   issuer)
102    {
103        tbsGen.setIssuer(issuer);
104    }
105
106    public void setNotBefore(
107        Date    date)
108    {
109        tbsGen.setStartDate(new Time(date));
110    }
111
112    public void setNotAfter(
113        Date    date)
114    {
115        tbsGen.setEndDate(new Time(date));
116    }
117
118    /**
119     * Set the subject distinguished name. The subject describes the entity associated with the public key.
120     */
121    public void setSubjectDN(
122        X500Principal   subject)
123    {
124        try
125        {
126            tbsGen.setSubject(new X509Principal(subject.getEncoded()));
127        }
128        catch (IOException e)
129        {
130            throw new IllegalArgumentException("can't process principal: " + e);
131        }
132    }
133
134    /**
135     * Set the subject distinguished name. The subject describes the entity associated with the public key.
136     */
137    public void setSubjectDN(
138        X509Name   subject)
139    {
140        tbsGen.setSubject(subject);
141    }
142
143    public void setPublicKey(
144        PublicKey       key)
145    {
146        try
147        {
148            tbsGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(key.getEncoded()));
149        }
150        catch (Exception e)
151        {
152            throw new IllegalArgumentException("unable to process key - " + e.toString());
153        }
154    }
155
156    /**
157     * Set the signature algorithm. This can be either a name or an OID, names
158     * are treated as case insensitive.
159     *
160     * @param signatureAlgorithm string representation of the algorithm name.
161     */
162    public void setSignatureAlgorithm(
163        String  signatureAlgorithm)
164    {
165        this.signatureAlgorithm = signatureAlgorithm;
166
167        try
168        {
169            sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
170        }
171        catch (Exception e)
172        {
173            throw new IllegalArgumentException("Unknown signature type requested");
174        }
175
176        sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
177
178        tbsGen.setSignature(sigAlgId);
179    }
180
181    /**
182     * generate an X509 certificate, based on the current issuer and subject
183     * using the default provider "BC".
184     * @deprecated use generate(key, "BC")
185     */
186    public X509Certificate generateX509Certificate(
187        PrivateKey      key)
188        throws SecurityException, SignatureException, InvalidKeyException
189    {
190        try
191        {
192            return generateX509Certificate(key, "BC", null);
193        }
194        catch (NoSuchProviderException e)
195        {
196            throw new SecurityException("BC provider not installed!");
197        }
198    }
199
200    /**
201     * generate an X509 certificate, based on the current issuer and subject
202     * using the default provider "BC" and the passed in source of randomness
203     * @deprecated use generate(key, random, "BC")
204     */
205    public X509Certificate generateX509Certificate(
206        PrivateKey      key,
207        SecureRandom    random)
208        throws SecurityException, SignatureException, InvalidKeyException
209    {
210        try
211        {
212            return generateX509Certificate(key, "BC", random);
213        }
214        catch (NoSuchProviderException e)
215        {
216            throw new SecurityException("BC provider not installed!");
217        }
218    }
219
220    /**
221     * generate an X509 certificate, based on the current issuer and subject,
222     * using the passed in provider for the signing, and the passed in source
223     * of randomness (if required).
224     * @deprecated use generate()
225     */
226    public X509Certificate generateX509Certificate(
227        PrivateKey      key,
228        String          provider)
229        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
230    {
231        return generateX509Certificate(key, provider, null);
232    }
233
234    /**
235     * generate an X509 certificate, based on the current issuer and subject,
236     * using the passed in provider for the signing, and the passed in source
237     * of randomness (if required).
238     * @deprecated use generate()
239     */
240    public X509Certificate generateX509Certificate(
241        PrivateKey      key,
242        String          provider,
243        SecureRandom    random)
244        throws NoSuchProviderException, SecurityException, SignatureException, InvalidKeyException
245    {
246        try
247        {
248            return generate(key, provider, random);
249        }
250        catch (NoSuchProviderException e)
251        {
252            throw e;
253        }
254        catch (SignatureException e)
255        {
256            throw e;
257        }
258        catch (InvalidKeyException e)
259        {
260            throw e;
261        }
262        catch (GeneralSecurityException e)
263        {
264            throw new SecurityException("exception: " + e);
265        }
266    }
267
268    /**
269     * generate an X509 certificate, based on the current issuer and subject
270     * using the default provider.
271     * <p>
272     * <b>Note:</b> this differs from the deprecated method in that the default provider is
273     * used - not "BC".
274     * </p>
275     */
276    public X509Certificate generate(
277        PrivateKey      key)
278        throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
279    {
280        return generate(key, (SecureRandom)null);
281    }
282
283    /**
284     * generate an X509 certificate, based on the current issuer and subject
285     * using the default provider and the passed in source of randomness
286     * <p>
287     * <b>Note:</b> this differs from the deprecated method in that the default provider is
288     * used - not "BC".
289     * </p>
290     */
291    public X509Certificate generate(
292        PrivateKey      key,
293        SecureRandom    random)
294        throws CertificateEncodingException, IllegalStateException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
295    {
296        TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
297        byte[] signature;
298
299        try
300        {
301            signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, key, random, tbsCert);
302        }
303        catch (IOException e)
304        {
305            throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
306        }
307
308        return generateJcaObject(tbsCert, signature);
309    }
310
311    /**
312     * generate an X509 certificate, based on the current issuer and subject,
313     * using the passed in provider for the signing, and the passed in source
314     * of randomness (if required).
315     */
316    public X509Certificate generate(
317        PrivateKey      key,
318        String          provider)
319        throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
320    {
321        return generate(key, provider, null);
322    }
323
324    /**
325     * generate an X509 certificate, based on the current issuer and subject,
326     * using the passed in provider for the signing, and the passed in source
327     * of randomness (if required).
328     */
329    public X509Certificate generate(
330        PrivateKey      key,
331        String          provider,
332        SecureRandom    random)
333        throws CertificateEncodingException, IllegalStateException, NoSuchProviderException, NoSuchAlgorithmException, SignatureException, InvalidKeyException
334    {
335        TBSCertificate tbsCert = tbsGen.generateTBSCertificate();
336        byte[] signature;
337
338        try
339        {
340            signature = X509Util.calculateSignature(sigOID, signatureAlgorithm, provider, key, random, tbsCert);
341        }
342        catch (IOException e)
343        {
344            throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
345        }
346
347        return generateJcaObject(tbsCert, signature);
348    }
349
350    private X509Certificate generateJcaObject(TBSCertificate tbsCert, byte[] signature)
351        throws CertificateEncodingException
352    {
353        ASN1EncodableVector v = new ASN1EncodableVector();
354
355        v.add(tbsCert);
356        v.add(sigAlgId);
357        v.add(new DERBitString(signature));
358
359        try
360        {
361            return (X509Certificate)certificateFactory.engineGenerateCertificate(
362                new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER)));
363        }
364        catch (Exception e)
365        {
366            throw new ExtCertificateEncodingException("exception producing certificate object", e);
367        }
368    }
369
370    /**
371     * Return an iterator of the signature names supported by the generator.
372     *
373     * @return an iterator containing recognised names.
374     */
375    public Iterator getSignatureAlgNames()
376    {
377        return X509Util.getAlgNames();
378    }
379}
380