1 /*
2  * @(#) $Id: IssueCertCommand.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.X509Certificate;
18import java.security.cert.CertPath;
19import java.io.*;
20
21import org.jstk.*;
22import org.jstk.asn1.DefASN1PullParser;
23import org.jstk.asn1.ASN1Seq;
24import org.jstk.asn1.ASN1Set;
25import org.jstk.asn1.ASN1Oid;
26import org.jstk.asn1.ASN1Explicit;
27import org.jstk.pki.SignedData;
28import org.jstk.pki.ContentInfo;
29import org.jstk.cert.ca.CADatabase;
30import org.jstk.cert.ca.FileBasedCADatabaseParams;
31import java.math.BigInteger;
32
33public class IssueCertCommand extends JSTKCommandAdapter {
34    private static HashMap defaults = new HashMap();
35    static {
36        defaults.put("csrfile", "my.csr");
37        defaults.put("cerfile", "my.cer");
38        defaults.put("capath", "0");
39        defaults.put("cadir", "cadir");
40        defaults.put("cpfmt", "pkcs7");
41        defaults.put("keyalg", "RSA");
42        defaults.put("keysize", "1024");
43        defaults.put("sigalg", "SHA1WithRSA");
44    }
45
46    public String briefDescription(){
47        String briefDesc = "issues certificate based on Certificate Signing Request (CSR)";
48        return briefDesc;
49    }
50
51    public String optionsDescription(){
52        String optionsDesc =
53            "  -cadir <cadir>      : CA directory.[" +
54            defaults.get("cadir") + "]\n" +
55            "  -csrfile <csrfile>  : CSR file.[" +
56            defaults.get("csrfile") + "]\n" +
57            "  -cerfile <cerfile>  : File to write issued Certificate.[" +
58            defaults.get("cerfile") + "]\n" +
59            "  -ca                 : Allow generated cert. to be used as a CA cert.\n" +
60            "  -capath <length>    : Certificate signing path length.[" +
61            defaults.get("capath") + "]\n" +
62            "  -keyalg <keyalg>    : Algorithm for Key Pair generation (RSA|DSA).[" +
63            defaults.get("keyalg") + "]\n" +
64            "  -keysize <keysize>  : Size of key (no. of bits).[" +
65            defaults.get("keysize") + "]\n" +
66            "  -sigalg <sigalg>    : Signature Algorithm. Should match Key Algorithm.[" +
67            defaults.get("sigalg") + "]\n" +
68            "  -password <passwd>  : Password for CA keystore.\n" +
69            "  -extnconf <conffile>: Configuration file to indicate extensions.\n" +
70            "  -cpfmt <cpfmt>      : Certificate Path format (pkcs7, pkipath or x509).[" +
71            defaults.get("cpfmt") + "]\n";
72        return optionsDesc;
73    }
74    public String[] useForms(){
75        String[] useForms = {
76            "[-csrfile <csrfile>] [-cerfile <cerfile>]"
77        };
78        return useForms;
79    }
80    public String[] sampleUses(){
81        String[] sampleUses = {
82            "",
83            "-csrfile test.csr -cerfile test.cer"
84        };
85        return sampleUses;
86    }
87
88
89    public Object execute(JSTKArgs args) throws JSTKException{
90        try {
91            args.setDefaults(defaults);
92            String csrfile = args.get("csrfile");
93            String cerfile = args.get("cerfile");
94            String cadir = args.get("cadir");
95            String cpfmt = args.get("cpfmt");
96            boolean caFlag = Boolean.valueOf(args.get("ca")).booleanValue();
97            int pathLen = Integer.parseInt(args.get("capath"));
98            String keyAlg = args.get("keyalg");
99            String sigAlg = args.get("sigalg");
00            String password = args.get("password");
01            String conffile = args.get("extnconf");
02            int keySize = Integer.parseInt(args.get("keysize"));
03
04            boolean pkcs7Format = false;
05            boolean pkipathFormat = false;
06            boolean x509Format = false;
07            if (cpfmt.equalsIgnoreCase("pkcs7"))
08                pkcs7Format = true;
09            else if (cpfmt.equalsIgnoreCase("pkipath"))
10                pkipathFormat = true;
11            else if (cpfmt.equalsIgnoreCase("x509"))
12                x509Format = true;
13            else
14                return new JSTKResult(null, false, "Invalid CertPath format: " + cpfmt);
15
16            if (password == null)
17                return new JSTKResult(null, false, "CA keystore password not specified. Use -password option.");
18
19            KeyUsage ku = null;
20            List eku = null;
21
22            if (conffile != null){  // Read conffile
23                Properties props = new Properties();
24                try {
25                    FileInputStream fis = new FileInputStream(conffile);
26                    props.load(fis);
27                } catch (IOException ioe){
28                    return new JSTKResult(null, false, "Cannot read extnconf file: " + ioe);
29                }
30
31                // Examine KeyUsage setting
32                String kuFlag = props.getProperty("KeyUsage");
33                if (kuFlag != null && kuFlag.equalsIgnoreCase("true")){
34                    ku = new KeyUsage();
35                    String kuString = null;
36                    int index = 0;
37                    while ((kuString = KeyUsage.getKeyUsageString(index)) != null){
38                        String kuStringFlag = props.getProperty("KeyUsage." + kuString);
39                        if (kuStringFlag != null && kuStringFlag.equalsIgnoreCase("true")){
40                            ku.setKeyUsage(index, true);
41                        }
42                        ++index;
43                    }
44                }
45
46                // Examine ExtendedKeyUsage setting
47                String ekuFlag = props.getProperty("ExtendedKeyUsage");
48                if (ekuFlag != null && ekuFlag.equalsIgnoreCase("true")){
49                    eku = new LinkedList();
50                    String ekuOId = null;
51                    int index = 0;
52                    while ((ekuOId = props.getProperty("ExtendedKeyUsage.ObjectId." + index)) != null){
53                        eku.add(ekuOId);
54                        ++index;
55                    }
56                }
57            }
58
59            FileBasedCADatabaseParams fbParams = new FileBasedCADatabaseParams(cadir);
60            fbParams.setPassword(password);
61
62            CADatabase cadb = CADatabase.getInstance("file", fbParams);
63            CertificateGenerator cg =
64                new CertificateGenerator((X509Certificate)cadb.getCACert(), cadb.getCAPrivateKey());
65
66            cg.setBasicConstraints(caFlag, pathLen);
67            cg.setSigAlg(sigAlg);
68            cg.setKeyUsage(ku);
69            cg.setExtendedKeyUsage(eku);
70
71
72            X509Certificate cert = cg.generateCertificate(csrfile, cadb.nextSerialNumber());
73            cadb.getIssuedCerts().add(cert);
74
75            byte[] outBytes;
76            if (pkipathFormat){
77                try {
78                    CertPath caCertPath = cadb.getCACertPath();
79                    byte[] caCertPathBytes = caCertPath.getEncoded();
80                    ASN1Seq cpSeq = new ASN1Seq();
81                    cpSeq.decode(DefASN1PullParser.getInstance(caCertPathBytes));
82                    byte[] certBytes = cert.getEncoded();
83                    ASN1Seq certSeq = new ASN1Seq();
84                    certSeq.decode(DefASN1PullParser.getInstance(certBytes));
85                    cpSeq.add(certSeq);
86                    outBytes = cpSeq.encode();
87                } catch (Exception e){
88                    throw new JSTKException("cannot form PkiPath certpath", e);
89                }
90            } else if (pkcs7Format){
91                try {
92                    CertPath caCertPath = cadb.getCACertPath();
93                    byte[] caCertPathBytes = caCertPath.getEncoded();
94                    ASN1Seq cpSeq = new ASN1Seq();
95                    cpSeq.decode(DefASN1PullParser.getInstance(caCertPathBytes));
96                    byte[] certBytes = cert.getEncoded();
97                    ASN1Seq certSeq = new ASN1Seq();
98                    certSeq.decode(DefASN1PullParser.getInstance(certBytes));
99                    ContentInfo ci = new ContentInfo();
00                    ASN1Oid contentType = ci.getContentType();
01                    contentType.setOid("1.2.840.113549.1.7.2");
02                    ASN1Explicit content = ci.getContent();
03                    SignedData sd = new SignedData();
04                    sd.getVersion().setValue(new java.math.BigInteger("1"));
05                    sd.getContentInfo().getContentType().setOid("1.2.840.113549.1.7.1");
06                    content.setInstance(sd);
07                    ASN1Set certs = sd.getCertificates();
08
09                    certs.add(certSeq);
10                    for (int i = cpSeq.size() - 1; i >= 0; i--)
11                        certs.add(cpSeq.elementAt(i));
12                    outBytes = ci.encode();
13                } catch (Exception e){
14                    throw new JSTKException("cannot form PKCS#7 certpath", e);
15                }
16            } else {
17                outBytes = cert.getEncoded();
18            }
19            FileOutputStream fos = new FileOutputStream(cerfile);
20            fos.write(outBytes);
21            fos.close();
22
23            return new JSTKResult(null, true, "Issued Certificate written to file: " + cerfile);
24        } catch (Exception exc){
25            throw new JSTKException("IssueCertCommand execution failed", exc);
26        }
27    }
28
29    public static void main(String[] args) throws Exception {
30        JSTKOptions opts = new JSTKOptions();
31        opts.parse(args, 0);
32        IssueCertCommand issueCertCmd = new IssueCertCommand();
33        JSTKResult result = (JSTKResult)issueCertCmd.execute(opts);
34        System.out.println(result.getText());
35        System.exit(result.isSuccess()? 0 : 1);
36    }
37}