001: package org.bouncycastle.x509;
002:
003: import org.bouncycastle.asn1.ASN1Encodable;
004: import org.bouncycastle.asn1.ASN1EncodableVector;
005: import org.bouncycastle.asn1.ASN1InputStream;
006: import org.bouncycastle.asn1.DERBitString;
007: import org.bouncycastle.asn1.DEREncodable;
008: import org.bouncycastle.asn1.DERInteger;
009: import org.bouncycastle.asn1.DERObjectIdentifier;
010: import org.bouncycastle.asn1.DERSequence;
011: import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
012: import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
013: import org.bouncycastle.asn1.x509.TBSCertificateStructure;
014: import org.bouncycastle.asn1.x509.Time;
015: import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
016: import org.bouncycastle.asn1.x509.X509CertificateStructure;
017: import org.bouncycastle.asn1.x509.X509ExtensionsGenerator;
018: import org.bouncycastle.asn1.x509.X509Name;
019: import org.bouncycastle.jce.X509Principal;
020: import org.bouncycastle.jce.provider.X509CertificateObject;
021: import org.bouncycastle.x509.extension.X509ExtensionUtil;
022:
023: import javax.security.auth.x500.X500Principal;
024: import java.io.IOException;
025: import java.math.BigInteger;
026: import java.security.GeneralSecurityException;
027: import java.security.InvalidKeyException;
028: import java.security.NoSuchAlgorithmException;
029: import java.security.NoSuchProviderException;
030: import java.security.PrivateKey;
031: import java.security.PublicKey;
032: import java.security.SecureRandom;
033: import java.security.SignatureException;
034: import java.security.cert.CertificateEncodingException;
035: import java.security.cert.CertificateParsingException;
036: import java.security.cert.X509Certificate;
037: import java.util.Date;
038: import java.util.Iterator;
039:
040: /**
041: * class to produce an X.509 Version 3 certificate.
042: */
043: public class X509V3CertificateGenerator {
044: private V3TBSCertificateGenerator tbsGen;
045: private DERObjectIdentifier sigOID;
046: private AlgorithmIdentifier sigAlgId;
047: private String signatureAlgorithm;
048: private X509ExtensionsGenerator extGenerator;
049:
050: public X509V3CertificateGenerator() {
051: tbsGen = new V3TBSCertificateGenerator();
052: extGenerator = new X509ExtensionsGenerator();
053: }
054:
055: /**
056: * reset the generator
057: */
058: public void reset() {
059: tbsGen = new V3TBSCertificateGenerator();
060: extGenerator.reset();
061: }
062:
063: /**
064: * set the serial number for the certificate.
065: */
066: public void setSerialNumber(BigInteger serialNumber) {
067: if (serialNumber.compareTo(BigInteger.ZERO) <= 0) {
068: throw new IllegalArgumentException(
069: "serial number must be a positive integer");
070: }
071:
072: tbsGen.setSerialNumber(new DERInteger(serialNumber));
073: }
074:
075: /**
076: * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
077: * certificate.
078: */
079: public void setIssuerDN(X500Principal issuer) {
080: try {
081: tbsGen.setIssuer(new X509Principal(issuer.getEncoded()));
082: } catch (IOException e) {
083: throw new IllegalArgumentException(
084: "can't process principal: " + e);
085: }
086: }
087:
088: /**
089: * Set the issuer distinguished name - the issuer is the entity whose private key is used to sign the
090: * certificate.
091: */
092: public void setIssuerDN(X509Name issuer) {
093: tbsGen.setIssuer(issuer);
094: }
095:
096: public void setNotBefore(Date date) {
097: tbsGen.setStartDate(new Time(date));
098: }
099:
100: public void setNotAfter(Date date) {
101: tbsGen.setEndDate(new Time(date));
102: }
103:
104: /**
105: * Set the subject distinguished name. The subject describes the entity associated with the public key.
106: */
107: public void setSubjectDN(X500Principal subject) {
108: try {
109: tbsGen.setSubject(new X509Principal(subject.getEncoded()));
110: } catch (IOException e) {
111: throw new IllegalArgumentException(
112: "can't process principal: " + e);
113: }
114: }
115:
116: /**
117: * Set the subject distinguished name. The subject describes the entity associated with the public key.
118: */
119: public void setSubjectDN(X509Name subject) {
120: tbsGen.setSubject(subject);
121: }
122:
123: public void setPublicKey(PublicKey key)
124: throws IllegalArgumentException {
125: try {
126: tbsGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo
127: .getInstance(new ASN1InputStream(key.getEncoded())
128: .readObject()));
129: } catch (Exception e) {
130: throw new IllegalArgumentException(
131: "unable to process key - " + e.toString());
132: }
133: }
134:
135: /**
136: * Set the signature algorithm. This can be either a name or an OID, names
137: * are treated as case insensitive.
138: *
139: * @param signatureAlgorithm string representation of the algorithm name.
140: */
141: public void setSignatureAlgorithm(String signatureAlgorithm) {
142: this .signatureAlgorithm = signatureAlgorithm;
143:
144: try {
145: sigOID = X509Util.getAlgorithmOID(signatureAlgorithm);
146: } catch (Exception e) {
147: throw new IllegalArgumentException(
148: "Unknown signature type requested: "
149: + signatureAlgorithm);
150: }
151:
152: sigAlgId = X509Util.getSigAlgID(sigOID, signatureAlgorithm);
153:
154: tbsGen.setSignature(sigAlgId);
155: }
156:
157: /**
158: * add a given extension field for the standard extensions tag (tag 3)
159: */
160: public void addExtension(String oid, boolean critical,
161: DEREncodable value) {
162: this
163: .addExtension(new DERObjectIdentifier(oid), critical,
164: value);
165: }
166:
167: /**
168: * add a given extension field for the standard extensions tag (tag 3)
169: */
170: public void addExtension(DERObjectIdentifier oid, boolean critical,
171: DEREncodable value) {
172: extGenerator.addExtension(oid, critical, value);
173: }
174:
175: /**
176: * add a given extension field for the standard extensions tag (tag 3)
177: * The value parameter becomes the contents of the octet string associated
178: * with the extension.
179: */
180: public void addExtension(String oid, boolean critical, byte[] value) {
181: this
182: .addExtension(new DERObjectIdentifier(oid), critical,
183: value);
184: }
185:
186: /**
187: * add a given extension field for the standard extensions tag (tag 3)
188: */
189: public void addExtension(DERObjectIdentifier oid, boolean critical,
190: byte[] value) {
191: extGenerator.addExtension(oid, critical, value);
192: }
193:
194: /**
195: * add a given extension field for the standard extensions tag (tag 3)
196: * copying the extension value from another certificate.
197: * @throws CertificateParsingException if the extension cannot be extracted.
198: */
199: public void copyAndAddExtension(String oid, boolean critical,
200: X509Certificate cert) throws CertificateParsingException {
201: byte[] extValue = cert.getExtensionValue(oid);
202:
203: if (extValue == null) {
204: throw new CertificateParsingException("extension " + oid
205: + " not present");
206: }
207:
208: try {
209: ASN1Encodable value = X509ExtensionUtil
210: .fromExtensionValue(extValue);
211:
212: this .addExtension(oid, critical, value);
213: } catch (IOException e) {
214: throw new CertificateParsingException(e.toString());
215: }
216: }
217:
218: /**
219: * add a given extension field for the standard extensions tag (tag 3)
220: * copying the extension value from another certificate.
221: * @throws CertificateParsingException if the extension cannot be extracted.
222: */
223: public void copyAndAddExtension(DERObjectIdentifier oid,
224: boolean critical, X509Certificate cert)
225: throws CertificateParsingException {
226: this .copyAndAddExtension(oid.getId(), critical, cert);
227: }
228:
229: /**
230: * generate an X509 certificate, based on the current issuer and subject
231: * using the default provider "BC".
232: * @deprecated use generate(key, "BC")
233: */
234: public X509Certificate generateX509Certificate(PrivateKey key)
235: throws SecurityException, SignatureException,
236: InvalidKeyException {
237: try {
238: return generateX509Certificate(key, "BC", null);
239: } catch (NoSuchProviderException e) {
240: throw new SecurityException("BC provider not installed!");
241: }
242: }
243:
244: /**
245: * generate an X509 certificate, based on the current issuer and subject
246: * using the default provider "BC", and the passed in source of randomness
247: * (if required).
248: * @deprecated use generate(key, random, "BC")
249: */
250: public X509Certificate generateX509Certificate(PrivateKey key,
251: SecureRandom random) throws SecurityException,
252: SignatureException, InvalidKeyException {
253: try {
254: return generateX509Certificate(key, "BC", random);
255: } catch (NoSuchProviderException e) {
256: throw new SecurityException("BC provider not installed!");
257: }
258: }
259:
260: /**
261: * generate an X509 certificate, based on the current issuer and subject,
262: * using the passed in provider for the signing.
263: * @deprecated use generate()
264: */
265: public X509Certificate generateX509Certificate(PrivateKey key,
266: String provider) throws NoSuchProviderException,
267: SecurityException, SignatureException, InvalidKeyException {
268: return generateX509Certificate(key, provider, null);
269: }
270:
271: /**
272: * generate an X509 certificate, based on the current issuer and subject,
273: * using the passed in provider for the signing and the supplied source
274: * of randomness, if required.
275: * @deprecated use generate()
276: */
277: public X509Certificate generateX509Certificate(PrivateKey key,
278: String provider, SecureRandom random)
279: throws NoSuchProviderException, SecurityException,
280: SignatureException, InvalidKeyException {
281: try {
282: return generate(key, provider, random);
283: } catch (NoSuchProviderException e) {
284: throw e;
285: } catch (SignatureException e) {
286: throw e;
287: } catch (InvalidKeyException e) {
288: throw e;
289: } catch (GeneralSecurityException e) {
290: throw new SecurityException("exception: " + e);
291: }
292: }
293:
294: /**
295: * generate an X509 certificate, based on the current issuer and subject
296: * using the default provider.
297: * <p>
298: * <b>Note:</b> this differs from the deprecated method in that the default provider is
299: * used - not "BC".
300: * </p>
301: */
302: public X509Certificate generate(PrivateKey key)
303: throws CertificateEncodingException, IllegalStateException,
304: NoSuchAlgorithmException, SignatureException,
305: InvalidKeyException {
306: return generate(key, (SecureRandom) null);
307: }
308:
309: /**
310: * generate an X509 certificate, based on the current issuer and subject
311: * using the default provider, and the passed in source of randomness
312: * (if required).
313: * <p>
314: * <b>Note:</b> this differs from the deprecated method in that the default provider is
315: * used - not "BC".
316: * </p>
317: */
318: public X509Certificate generate(PrivateKey key, SecureRandom random)
319: throws CertificateEncodingException, IllegalStateException,
320: NoSuchAlgorithmException, SignatureException,
321: InvalidKeyException {
322: TBSCertificateStructure tbsCert = generateTbsCert();
323: byte[] signature;
324:
325: try {
326: signature = X509Util.calculateSignature(sigOID,
327: signatureAlgorithm, key, random, tbsCert);
328: } catch (IOException e) {
329: throw new ExtCertificateEncodingException(
330: "exception encoding TBS cert", e);
331: }
332:
333: try {
334: return generateJcaObject(tbsCert, signature);
335: } catch (CertificateParsingException e) {
336: throw new ExtCertificateEncodingException(
337: "exception producing certificate object", e);
338: }
339: }
340:
341: /**
342: * generate an X509 certificate, based on the current issuer and subject,
343: * using the passed in provider for the signing.
344: */
345: public X509Certificate generate(PrivateKey key, String provider)
346: throws CertificateEncodingException, IllegalStateException,
347: NoSuchProviderException, NoSuchAlgorithmException,
348: SignatureException, InvalidKeyException {
349: return generate(key, provider, null);
350: }
351:
352: /**
353: * generate an X509 certificate, based on the current issuer and subject,
354: * using the passed in provider for the signing and the supplied source
355: * of randomness, if required.
356: */
357: public X509Certificate generate(PrivateKey key, String provider,
358: SecureRandom random) throws CertificateEncodingException,
359: IllegalStateException, NoSuchProviderException,
360: NoSuchAlgorithmException, SignatureException,
361: InvalidKeyException {
362: TBSCertificateStructure tbsCert = generateTbsCert();
363: byte[] signature;
364:
365: try {
366: signature = X509Util.calculateSignature(sigOID,
367: signatureAlgorithm, provider, key, random, tbsCert);
368: } catch (IOException e) {
369: throw new ExtCertificateEncodingException(
370: "exception encoding TBS cert", e);
371: }
372:
373: try {
374: return generateJcaObject(tbsCert, signature);
375: } catch (CertificateParsingException e) {
376: throw new ExtCertificateEncodingException(
377: "exception producing certificate object", e);
378: }
379: }
380:
381: private TBSCertificateStructure generateTbsCert() {
382: if (!extGenerator.isEmpty()) {
383: tbsGen.setExtensions(extGenerator.generate());
384: }
385:
386: return tbsGen.generateTBSCertificate();
387: }
388:
389: private X509Certificate generateJcaObject(
390: TBSCertificateStructure tbsCert, byte[] signature)
391: throws CertificateParsingException {
392: ASN1EncodableVector v = new ASN1EncodableVector();
393:
394: v.add(tbsCert);
395: v.add(sigAlgId);
396: v.add(new DERBitString(signature));
397:
398: return new X509CertificateObject(new X509CertificateStructure(
399: new DERSequence(v)));
400: }
401:
402: /**
403: * Return an iterator of the signature names supported by the generator.
404: *
405: * @return an iterator containing recognised names.
406: */
407: public Iterator getSignatureAlgNames() {
408: return X509Util.getAlgNames();
409: }
410: }
|