1
10package org.jstk.cert.ca;
11
12import java.security.cert.Certificate;
13import java.security.cert.CertificateFactory;
14import java.security.cert.CertPath;
15import java.security.PrivateKey;
16import java.security.KeyStore;
17import java.security.KeyStoreException;
18import java.security.NoSuchAlgorithmException;
19import java.math.BigInteger;
20import java.util.Vector;
21import java.io.File;
22import java.io.FileInputStream;
23import java.io.FileOutputStream;
24import java.io.FileReader;
25import java.io.FileWriter;
26import java.io.BufferedReader;
27import java.io.PrintWriter;
28import java.io.IOException;
29
30public class FileBasedCADatabase implements CADatabaseSpi {
31 public static final String KEYSTORE = "ca.ks";
32 public static final String STORETYPE = "JCEKS";
33 public static final String ALIAS = "cakey";
34 public static final String STOREPASS = "changeit";
35 public static final String KEYPASS = "changeit";
36 public static final String ISSUED_DIR = "issued";
37 public static final String REVOKED_DIR = "revoked";
38 public static final String ISSUED_CERTS = "issued.certs";
39 public static final String REVOKED_CERTS = "revoked.certs";
40 public static final String SERIALNO_FILE = "serialno.cur";
41 public static final String START_SERIALNO = "999";
42
43 public static final BigInteger ONE = new BigInteger("1");
44
45 private String ksFileName;
46 private String serialNoFileName;
47 private String caDirName;
48 private PrivateKey caPrivateKey;
49 private Certificate caCert;
50 private CertPath caCertPath;
51 private File caDir;
52 private boolean initialized = false;
53 private String password;
54
55 public FileBasedCADatabase(FileBasedCADatabaseParams params) throws CADatabaseException {
56 String caDirName = params.getCADirName();
57 try {
58 password = params.getPassword();
59 if (!params.getCreateCA()){
60 init(caDirName);
61 } else {
62 create(caDirName, params.getCACerts(), params.getCAPrivateKey());
63 }
64 } catch (CADatabaseException de){
65 throw de;
66 } catch (Exception e){
67 throw new CADatabaseException("FileBasedCADatabase constructor failed.", e);
68 }
69 initialized = true;
70 }
71
72 private void init(String caDirName) throws Exception {
73
74 this.caDirName = caDirName;
76 caDir = new File(caDirName);
77 if (!caDir.exists()){
78 throw new CADatabaseException("Directory not found: " + caDirName);
79 } else if (!caDir.isDirectory()){
80 throw new CADatabaseException("Not a directory: " + caDirName);
81 } else if (!caDir.canRead()){
82 throw new CADatabaseException("No read permission: " + caDirName);
83 } else if (!caDir.canWrite()){
84 throw new CADatabaseException("No write permission: " + caDirName);
85 }
86
87 ksFileName = caDirName + File.separator + KEYSTORE;
89 FileInputStream fis = new FileInputStream(ksFileName);
90
91 KeyStore caKeyStore = KeyStore.getInstance(STORETYPE);
92 caKeyStore.load(fis, password.toCharArray());
93 fis.close();
94 if (caKeyStore.isKeyEntry(ALIAS)) {
95 caPrivateKey = (PrivateKey)caKeyStore.getKey(ALIAS, password.toCharArray());
96 caCert = caKeyStore.getCertificate(ALIAS);
97 Certificate[] caCerts = caKeyStore.getCertificateChain(ALIAS);
98 if (caCert == null || caCerts == null){
99 throw new CADatabaseException("Certificate not found in keystore: " + ksFileName);
00 }
01 CertificateFactory certFac = CertificateFactory.getInstance("X.509");
02 Vector certVec = new Vector();
03 for (int i = 0; i < caCerts.length; i++){
04 certVec.add(caCerts[i]);
05 }
06 caCertPath = certFac.generateCertPath(certVec);
07 } else {
08 throw new CADatabaseException("PrivateKey not found in keystore: " + ksFileName);
09 }
10
11 serialNoFileName = caDirName + File.separator + SERIALNO_FILE;
13 File serialNoFile = new File(serialNoFileName);
14 if (!serialNoFile.exists()){
15 PrintWriter pw = new PrintWriter(new FileWriter(serialNoFileName));
16 pw.println(START_SERIALNO);
17 pw.close();
18 }
19 }
20
21 private void create(String caDirName, Certificate[] caCerts, PrivateKey caKey) throws Exception {
22
23 this.caDirName = caDirName;
25 caDir = new File(caDirName);
26 if (caDir.exists()){
27 throw new CADatabaseException("Directory exists: " + caDirName);
28 }
29 if (!caDir.mkdirs()){
30 throw new CADatabaseException("Directory creation failed: " + caDirName);
31 }
32
33 ksFileName = caDirName + File.separator + KEYSTORE;
35 FileOutputStream fos = new FileOutputStream(ksFileName);
36
37 KeyStore caKeyStore = KeyStore.getInstance(STORETYPE);
38 caKeyStore.load(null, password.toCharArray());
39 caKeyStore.setKeyEntry(ALIAS, caKey, password.toCharArray(), caCerts);
40
41 caKeyStore.store(fos, password.toCharArray());
42 fos.close();
43
44 String issuedCertsDirName = caDirName + File.separator + ISSUED_DIR;
45 File issuedCertsDir = new File(issuedCertsDirName);
46 issuedCertsDir.mkdirs();
47
48 String revokedCertsDirName = caDirName + File.separator + REVOKED_DIR;
49 File revokedCertsDir = new File(revokedCertsDirName);
50 revokedCertsDir.mkdirs();
51
52 serialNoFileName = caDirName + File.separator + SERIALNO_FILE;
54 File serialNoFile = new File(serialNoFileName);
55 if (!serialNoFile.exists()){
56 PrintWriter pw = new PrintWriter(new FileWriter(serialNoFileName));
57 pw.println(START_SERIALNO);
58 pw.close();
59 }
60 }
61
62 public IssuedCerts getIssuedCerts(){
63 String issuedCertsFileName = caDirName + File.separator + ISSUED_CERTS;
64 String issuedCertsDirName = caDirName + File.separator + ISSUED_DIR;
65 return new FileBasedIssuedCerts(issuedCertsFileName, issuedCertsDirName);
66 }
67
68 public RevokedCerts getRevokedCerts(){
69 String revokedCertsFileName = caDirName + File.separator + REVOKED_CERTS;
70 String revokedCertsDirName = caDirName + File.separator + REVOKED_DIR;
71 return new FileBasedRevokedCerts(revokedCertsFileName, revokedCertsDirName);
72 }
73
74 public Certificate getCACert(){
75 return caCert;
76 }
77 public CertPath getCACertPath(){
78 return caCertPath;
79 }
80 public PrivateKey getCAPrivateKey(){
81 return caPrivateKey;
82 }
83
84 public synchronized BigInteger nextSerialNumber() throws CADatabaseException {
85 try {
86 BufferedReader br = new BufferedReader(new FileReader(serialNoFileName));
87 String serialNoString = br.readLine();
88 BigInteger serialNo = new BigInteger(serialNoString);
89 br.close();
90 serialNo = serialNo.add(ONE);
91 PrintWriter pw = new PrintWriter(new FileWriter(serialNoFileName));
92 pw.println(serialNo.toString());
93 pw.close();
94 return serialNo;
95 } catch (Exception e){
96 throw new CADatabaseException("cannot get next serial number.", e);
97 }
98 }
99}
00
01