1 /*
2  * @(#) $Id: CertificateGenerator.java,v 1.4 2003/07/08 08:13:52 pankaj Exp $
3  *
4  * Copyright (c) 2002-03 by Pankaj Kumar (http://www.pankaj-k.net). 
5  * All rights reserved.
6  *
7  * The license governing the use of this file can be found in the 
8  * root directory of the containing software.
9  */
10package org.jstk.cert;
11
12import java.util.*;
13import java.security.Signature;
14import java.security.KeyPair;
15import java.security.PrivateKey;
16import java.security.PublicKey;
17import java.security.cert.Certificate;
18import java.security.cert.CertificateFactory;
19import java.security.cert.X509Certificate;
20import java.io.ByteArrayInputStream;
21import java.io.InputStream;
22
23import org.jstk.JSTKException;
24import org.jstk.pki.CSR;
25import org.jstk.pki.TBSCertificate;
26import org.jstk.pki.AlgorithmIdentifier;
27import org.jstk.pki.Name;
28import org.jstk.pki.Validity;
29import org.jstk.pki.SubjectPublicKeyInfo;
30import org.jstk.asn1.*;
31import java.math.BigInteger;
32import javax.security.auth.x500.X500Principal;
33
34public class CertificateGenerator {
35    public final static int DEFAULT_VALIDITY_PERIOD = 365; // No. of days.
36    public final static String DEFAULT_SIGNATURE_ALGORITHM = "dsaWithSHA1";
37
38    private X509Certificate issuerCert = null;
39    private PrivateKey issuerKey = null;
40    private boolean caFlag = false;
41    private int pathLen = 0;
42    private String sigAlg = DEFAULT_SIGNATURE_ALGORITHM;
43    private KeyUsage keyUsage = null;
44    private List extendedKeyUsage = null;
45
46    public CertificateGenerator(){
47    }
48
49    public CertificateGenerator(X509Certificate issuerCert, PrivateKey issuerKey){
50        this.issuerCert = issuerCert;
51        this.issuerKey = issuerKey;
52    }
53
54    public X509Certificate generateCertificate(String csrFile, BigInteger serialNo) throws JSTKException {
55        return generateCertificate(csrFile, serialNo, DEFAULT_VALIDITY_PERIOD);
56    }
57
58    public void setBasicConstraints(boolean caFlag, int pathLen){
59        this.caFlag = caFlag;
60        this.pathLen = pathLen;
61    }
62
63    public void setSigAlg(String sigAlg){
64        this.sigAlg = sigAlg;
65    }
66
67    public void setKeyUsage(KeyUsage keyUsage){
68        this.keyUsage = keyUsage;
69    }
70
71    public void setExtendedKeyUsage(List extendedKeyUsage){
72        this.extendedKeyUsage = extendedKeyUsage;
73    }
74
75    public X509Certificate generateCertificate(String csrFile, BigInteger serialNo,
76            int noDays) throws JSTKException {
77        Calendar cal = Calendar.getInstance();
78        Date notBefore = cal.getTime();
79        cal.add(Calendar.DATE, noDays);
80        Date notAfter = cal.getTime();
81        return generateCertificate(csrFile, serialNo, notBefore,
82                        notAfter, sigAlg);
83    }
84
85    public X509Certificate generateCertificate(String csrFile, BigInteger serialNo,
86            Date notBefore, Date notAfter, String sigAlgorithm) throws JSTKException{
87        if (issuerCert == null || issuerKey == null){
88            throw new JSTKException("CertificateGenerator not initialized.");
89        }
90        try {
91            // Get the CSR
92            InputStream csris = org.jstk.pem.PEMData.getDERInputStream(csrFile);
93            CSR csr = new CSR();
94            DefASN1PullParser parser = new DefASN1PullParser();
95            parser.setInput(csris);
96            csr.decode(parser);
97
98            // Setup Certificate.
99            org.jstk.pki.Certificate cert = new org.jstk.pki.Certificate();
00            TBSCertificate tbsCertificate = cert.getTBSCertificate();
01
02            ASN1Integer version = tbsCertificate.getVersion().getVersion();
03            version.setValue((new BigInteger("2")).toByteArray());
04
05            tbsCertificate.getSerialNumber().setValue(serialNo.toByteArray());
06
07            AlgorithmIdentifier algorithmId = tbsCertificate.getAlgorithm();
08            algorithmId.setOid(OidMap.getId(sigAlgorithm));
09            algorithmId.setParams(new ASN1Null());
10
11            // Setup Issuer
12            javax.security.auth.x500.X500Principal p = issuerCert.getSubjectX500Principal();
13            Name issuer = tbsCertificate.getIssuer();
14            issuer.setValue(p.getEncoded());
15            issuer.setIgnoreMembers(true);
16
17            // Setup validity period
18            Validity validity = tbsCertificate.getValidity();
19            validity.getNotBefore().setDate(notBefore);
20            validity.getNotAfter().setDate(notAfter);
21
22            // Setup Subject
23            Name subject = tbsCertificate.getSubject();
24            subject.reinitialize(csr.getCSRInfo().getSubject());
25            SubjectPublicKeyInfo publicKeyInfo = tbsCertificate.getSubjectPublicKeyInfo();
26            publicKeyInfo.reinitialize(csr.getCSRInfo().getPublicKeyInfo());
27
28            // Setup Extensions
29            ASN1Explicit extensions = tbsCertificate.getExtensions();
30            ASN1Seq extnsSeq = new ASN1Seq();
31
32            ASN1Seq basicConsExtn = new ASN1Seq();
33            basicConsExtn.setValue(encodeBasicConstraints());
34            basicConsExtn.setIgnoreMembers(true);
35            extnsSeq.add(basicConsExtn);
36
37            if (keyUsage != null){  // Add KeyUsage extension.
38                extnsSeq.add(createKeyUsage());
39            }
40
41            if (extendedKeyUsage != null){  // Add KeyUsage extension.
42                extnsSeq.add(createExtendedKeyUsage());
43            }
44
45            extensions.setInstance(extnsSeq);
46
47            // Setup Algorithm identifier. Note that this is duplicate !! previous one
48            // gets signed ( cannot be tampered ).
49            AlgorithmIdentifier algorithmId1 = cert.getAlgorithm();
50            algorithmId1.setOid(OidMap.getId(sigAlgorithm));
51            algorithmId1.setParams(new ASN1Null());
52
53            X509Certificate c  = signCertificate(cert, sigAlgorithm, issuerKey);
54            return c;
55        } catch (Exception exc){
56            throw new JSTKException("generateCertificate failed", exc);
57        }
58    }
59
60    public X509Certificate generateSelfSignedCertificate(String dn, KeyPair kp, BigInteger serialNo,
61            int noDays) throws JSTKException {
62        Calendar cal = Calendar.getInstance();
63        Date notBefore = cal.getTime();
64        cal.add(Calendar.DATE, noDays);
65        Date notAfter = cal.getTime();
66        return generateSelfSignedCertificate(dn, kp, serialNo, notBefore,
67                        notAfter, sigAlg);
68    }
69
70    public X509Certificate generateSelfSignedCertificate(String dn, KeyPair kp, BigInteger serialNo,
71            Date notBefore, Date notAfter, String sigAlgorithm) throws JSTKException{
72        try {
73            // Setup Certificate.
74            org.jstk.pki.Certificate cert = new org.jstk.pki.Certificate();
75            TBSCertificate tbsCertificate = cert.getTBSCertificate();
76
77            ASN1Integer version = tbsCertificate.getVersion().getVersion();
78            version.setValue((new BigInteger("2")).toByteArray());
79
80            tbsCertificate.getSerialNumber().setValue(serialNo.toByteArray());
81
82            AlgorithmIdentifier algorithmId = tbsCertificate.getAlgorithm();
83            algorithmId.setOid(OidMap.getId(sigAlgorithm));
84            algorithmId.setParams(new ASN1Null());
85
86            // Setup Issuer
87            X500Principal p = new X500Principal(dn);
88            Name issuer = tbsCertificate.getIssuer();
89            issuer.setValue(p.getEncoded());
90            issuer.setIgnoreMembers(true);
91
92            // Setup validity period
93            Validity validity = tbsCertificate.getValidity();
94            validity.getNotBefore().setDate(notBefore);
95            validity.getNotAfter().setDate(notAfter);
96
97            // Setup Subject
98            Name subject = tbsCertificate.getSubject();
99            subject.setValue(p.getEncoded());
00            subject.setIgnoreMembers(true);
01            SubjectPublicKeyInfo publicKeyInfo = tbsCertificate.getSubjectPublicKeyInfo();
02            byte[] encoded = kp.getPublic().getEncoded();
03            publicKeyInfo.setValue(encoded);
04            publicKeyInfo.setIgnoreMembers(true);
05
06            // Setup Extensions
07            ASN1Explicit extensions = tbsCertificate.getExtensions();
08            ASN1Seq extnsSeq = new ASN1Seq();
09
10            ASN1Seq basicConsExtn = new ASN1Seq();
11            basicConsExtn.setValue(encodeBasicConstraints());
12            basicConsExtn.setIgnoreMembers(true);
13            extnsSeq.add(basicConsExtn);
14
15            extensions.setInstance(extnsSeq);
16
17            // Setup Algorithm identifier. Note that this is duplicate !! previous one
18            // gets signed ( cannot be tampered ).
19            AlgorithmIdentifier algorithmId1 = cert.getAlgorithm();
20            algorithmId1.setOid(OidMap.getId(sigAlgorithm));
21            algorithmId1.setParams(new ASN1Null());
22
23            X509Certificate c  = signCertificate(cert, sigAlgorithm, kp.getPrivate());
24            return c;
25        } catch (Exception exc){
26            throw new JSTKException("generateCertificate failed", exc);
27        }
28    }
29
30    byte[] encodeBasicConstraints(){
31        ASN1Seq basicConsExtn = new ASN1Seq();
32        ASN1Oid oid = new ASN1Oid();
33        oid.setOid("2.5.29.19");
34
35        ASN1Seq basicConstraints = new ASN1Seq();
36        ASN1Boolean ab = new ASN1Boolean();
37        ab.setValue(caFlag);
38        ASN1Integer ai = new ASN1Integer();
39        ai.setValue(new BigInteger(Integer.toString(pathLen)));
40        basicConstraints.add(ab);
41        basicConstraints.add(ai);
42
43        ASN1OctetString aos = new ASN1OctetString();
44        aos.setValue(basicConstraints.encode());
45
46        basicConsExtn.add(oid);
47        basicConsExtn.add(aos);
48        return basicConsExtn.encode();
49    }
50
51    ASN1Seq createKeyUsage(){
52        ASN1Seq keyUsageExtn = new ASN1Seq();
53        ASN1Oid oid = new ASN1Oid();
54        oid.setOid("2.5.29.15");
55        ASN1BitString abs = new ASN1BitString();
56        abs.setValue(keyUsage.getBitString(), keyUsage.getNumUnusedBits());
57
58        ASN1OctetString aos = new ASN1OctetString();
59        aos.setValue(abs.encode());
60
61        keyUsageExtn.add(oid);
62        keyUsageExtn.add(aos);
63        return keyUsageExtn;
64    }
65
66    ASN1Seq createExtendedKeyUsage(){
67        ASN1Seq ekuExtn = new ASN1Seq();
68        ASN1Oid oid = new ASN1Oid();
69        oid.setOid("2.5.29.37");
70        ASN1Seq ids = new ASN1Seq();
71        for (int i = 0; i < extendedKeyUsage.size(); i++){
72            ASN1Oid id = new ASN1Oid();
73            id.setOid((String)extendedKeyUsage.get(i));
74            ids.add(id);
75        }
76
77        ASN1OctetString aos = new ASN1OctetString();
78        aos.setValue(ids.encode());
79
80        ekuExtn.add(oid);
81        ekuExtn.add(aos);
82        return ekuExtn;
83    }
84
85    X509Certificate signCertificate(org.jstk.pki.Certificate cert, String sigAlgorithm,
86            PrivateKey prvKey) throws Exception {
87        TBSCertificate tbsCertificate = cert.getTBSCertificate();
88
89        // Get the DER encoded TBSCertificate and sign it.
90        byte[] encodedTBSCertificate = tbsCertificate.encode();
91        Signature sig = Signature.getInstance(sigAlgorithm);
92        sig.initSign(prvKey);
93        sig.update(encodedTBSCertificate);
94        byte[] sigbytes = sig.sign();
95
96        ASN1BitString signatureBytes = cert.getSignatureBytes();
97        signatureBytes.setValue(sigbytes);
98
99        byte[] certBytes = cert.encode();
00
01        ByteArrayInputStream bais = new ByteArrayInputStream(certBytes);
02        CertificateFactory cf = CertificateFactory.getInstance("X.509");
03        X509Certificate c = (X509Certificate)cf.generateCertificate(bais);
04        return c;
05    }
06}