1 package org.bouncycastle.cert;
2 
3 import java.math.BigInteger;
4 import java.util.Date;
5 import java.util.Locale;
6 
7 import org.bouncycastle.asn1.ASN1Encodable;
8 import org.bouncycastle.asn1.ASN1Integer;
9 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
10 import org.bouncycastle.asn1.x500.X500Name;
11 import org.bouncycastle.asn1.x509.Certificate;
12 import org.bouncycastle.asn1.x509.Extension;
13 import org.bouncycastle.asn1.x509.ExtensionsGenerator;
14 import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
15 import org.bouncycastle.asn1.x509.Time;
16 import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
17 import org.bouncycastle.operator.ContentSigner;
18 
19 
20 /**
21  * class to produce an X.509 Version 3 certificate.
22  */
23 public class X509v3CertificateBuilder
24 {
25     private V3TBSCertificateGenerator   tbsGen;
26     private ExtensionsGenerator extGenerator;
27 
28     /**
29      * Create a builder for a version 3 certificate.
30      *
31      * @param issuer the certificate issuer
32      * @param serial the certificate serial number
33      * @param notBefore the date before which the certificate is not valid
34      * @param notAfter the date after which the certificate is not valid
35      * @param subject the certificate subject
36      * @param publicKeyInfo the info structure for the public key to be associated with this certificate.
37      */
X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, SubjectPublicKeyInfo publicKeyInfo)38     public X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, X500Name subject, SubjectPublicKeyInfo publicKeyInfo)
39     {
40         this(issuer, serial, new Time(notBefore), new Time(notAfter), subject, publicKeyInfo);
41     }
42 
43     /**
44      * Create a builder for a version 3 certificate. You may need to use this constructor if the default locale
45      * doesn't use a Gregorian calender so that the Time produced is compatible with other ASN.1 implementations.
46      *
47      * @param issuer the certificate issuer
48      * @param serial the certificate serial number
49      * @param notBefore the date before which the certificate is not valid
50      * @param notAfter the date after which the certificate is not valid
51      * @param dateLocale locale to be used for date interpretation.
52      * @param subject the certificate subject
53      * @param publicKeyInfo the info structure for the public key to be associated with this certificate.
54      */
X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, Locale dateLocale, X500Name subject, SubjectPublicKeyInfo publicKeyInfo)55     public X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Date notBefore, Date notAfter, Locale dateLocale, X500Name subject, SubjectPublicKeyInfo publicKeyInfo)
56     {
57         this(issuer, serial, new Time(notBefore, dateLocale), new Time(notAfter, dateLocale), subject, publicKeyInfo);
58     }
59 
60     /**
61      * Create a builder for a version 3 certificate.
62      *
63      * @param issuer the certificate issuer
64      * @param serial the certificate serial number
65      * @param notBefore the Time before which the certificate is not valid
66      * @param notAfter the Time after which the certificate is not valid
67      * @param subject the certificate subject
68      * @param publicKeyInfo the info structure for the public key to be associated with this certificate.
69      */
X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Time notBefore, Time notAfter, X500Name subject, SubjectPublicKeyInfo publicKeyInfo)70     public X509v3CertificateBuilder(X500Name issuer, BigInteger serial, Time notBefore, Time notAfter, X500Name subject, SubjectPublicKeyInfo publicKeyInfo)
71     {
72         tbsGen = new V3TBSCertificateGenerator();
73         tbsGen.setSerialNumber(new ASN1Integer(serial));
74         tbsGen.setIssuer(issuer);
75         tbsGen.setStartDate(notBefore);
76         tbsGen.setEndDate(notAfter);
77         tbsGen.setSubject(subject);
78         tbsGen.setSubjectPublicKeyInfo(publicKeyInfo);
79 
80         extGenerator = new ExtensionsGenerator();
81     }
82 
83     /**
84      * Set the subjectUniqueID - note: it is very rare that it is correct to do this.
85      *
86      * @param uniqueID a boolean array representing the bits making up the subjectUniqueID.
87      * @return this builder object.
88      */
setSubjectUniqueID(boolean[] uniqueID)89     public X509v3CertificateBuilder setSubjectUniqueID(boolean[] uniqueID)
90     {
91         tbsGen.setSubjectUniqueID(CertUtils.booleanToBitString(uniqueID));
92 
93         return this;
94     }
95 
96     /**
97      * Set the issuerUniqueID - note: it is very rare that it is correct to do this.
98      *
99      * @param uniqueID a boolean array representing the bits making up the issuerUniqueID.
100      * @return this builder object.
101      */
setIssuerUniqueID(boolean[] uniqueID)102     public X509v3CertificateBuilder setIssuerUniqueID(boolean[] uniqueID)
103     {
104         tbsGen.setIssuerUniqueID(CertUtils.booleanToBitString(uniqueID));
105 
106         return this;
107     }
108 
109     /**
110      * Add a given extension field for the standard extensions tag (tag 3)
111      *
112      * @param oid the OID defining the extension type.
113      * @param isCritical true if the extension is critical, false otherwise.
114      * @param value the ASN.1 structure that forms the extension's value.
115      * @return this builder object.
116      */
addExtension( ASN1ObjectIdentifier oid, boolean isCritical, ASN1Encodable value)117     public X509v3CertificateBuilder addExtension(
118         ASN1ObjectIdentifier oid,
119         boolean isCritical,
120         ASN1Encodable value)
121         throws CertIOException
122     {
123         CertUtils.addExtension(extGenerator, oid, isCritical, value);
124 
125         return this;
126     }
127 
128     /**
129      * Add a given extension field for the standard extensions tag (tag 3).
130      *
131      * @param extension the full extension value.
132      * @return this builder object.
133      */
addExtension( Extension extension)134     public X509v3CertificateBuilder addExtension(
135         Extension extension)
136         throws CertIOException
137     {
138         extGenerator.addExtension(extension);
139 
140         return this;
141     }
142 
143     /**
144      * Add a given extension field for the standard extensions tag (tag 3) using a byte encoding of the
145      * extension value.
146      *
147      * @param oid the OID defining the extension type.
148      * @param isCritical true if the extension is critical, false otherwise.
149      * @param encodedValue a byte array representing the encoding of the extension value.
150      * @return this builder object.
151      */
addExtension( ASN1ObjectIdentifier oid, boolean isCritical, byte[] encodedValue)152     public X509v3CertificateBuilder addExtension(
153         ASN1ObjectIdentifier oid,
154         boolean isCritical,
155         byte[] encodedValue)
156         throws CertIOException
157     {
158         extGenerator.addExtension(oid, isCritical, encodedValue);
159 
160         return this;
161     }
162 
163     /**
164      * Add a given extension field for the standard extensions tag (tag 3)
165      * copying the extension value from another certificate.
166      *
167      * @param oid the OID defining the extension type.
168      * @param isCritical true if the copied extension is to be marked as critical, false otherwise.
169      * @param certHolder the holder for the certificate that the extension is to be copied from.
170      * @return this builder object.
171      */
copyAndAddExtension( ASN1ObjectIdentifier oid, boolean isCritical, X509CertificateHolder certHolder)172     public X509v3CertificateBuilder copyAndAddExtension(
173         ASN1ObjectIdentifier oid,
174         boolean isCritical,
175         X509CertificateHolder certHolder)
176     {
177         Certificate cert = certHolder.toASN1Structure();
178 
179         Extension extension = cert.getTBSCertificate().getExtensions().getExtension(oid);
180 
181         if (extension == null)
182         {
183             throw new NullPointerException("extension " + oid + " not present");
184         }
185 
186         extGenerator.addExtension(oid, isCritical, extension.getExtnValue().getOctets());
187 
188         return this;
189     }
190 
191     /**
192      * Generate an X.509 certificate, based on the current issuer and subject
193      * using the passed in signer.
194      *
195      * @param signer the content signer to be used to generate the signature validating the certificate.
196      * @return a holder containing the resulting signed certificate.
197      */
build( ContentSigner signer)198     public X509CertificateHolder build(
199         ContentSigner signer)
200     {
201         tbsGen.setSignature(signer.getAlgorithmIdentifier());
202 
203         if (!extGenerator.isEmpty())
204         {
205             tbsGen.setExtensions(extGenerator.generate());
206         }
207 
208         return CertUtils.generateFullCert(signer, tbsGen.generateTBSCertificate());
209     }
210 }