]> WPIA git - gigi.git/blob - src/org/cacert/gigi/Certificate.java
[DB-Struct] Implement some certificate types.
[gigi.git] / src / org / cacert / gigi / Certificate.java
1 package org.cacert.gigi;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.io.InputStream;
8 import java.security.GeneralSecurityException;
9 import java.security.cert.CertificateFactory;
10 import java.security.cert.X509Certificate;
11 import java.sql.PreparedStatement;
12 import java.sql.ResultSet;
13 import java.sql.SQLException;
14
15 import org.cacert.gigi.database.DatabaseConnection;
16 import org.cacert.gigi.util.Job;
17 import org.cacert.gigi.util.Job.JobType;
18 import org.cacert.gigi.util.KeyStorage;
19 import org.cacert.gigi.util.Notary;
20
21 public class Certificate {
22
23     public enum CSRType {
24         CSR, SPKAC;
25     }
26
27     private int id;
28
29     private int ownerId;
30
31     private String serial;
32
33     private String dn;
34
35     private String md;
36
37     private String csrName;
38
39     private String crtName;
40
41     private String csr = null;
42
43     private CSRType csrType;
44
45     public Certificate(int ownerId, String dn, String md, String csr, CSRType csrType) {
46         this.ownerId = ownerId;
47         this.dn = dn;
48         this.md = md;
49         this.csr = csr;
50         this.csrType = csrType;
51     }
52
53     private Certificate(String serial) {
54         try {
55             PreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT id,subject, md, csr_name, crt_name,memid FROM `emailcerts` WHERE serial=?");
56             ps.setString(1, serial);
57             ResultSet rs = ps.executeQuery();
58             if ( !rs.next()) {
59                 throw new IllegalArgumentException("Invalid mid " + serial);
60             }
61             this.id = rs.getInt(1);
62             dn = rs.getString(2);
63             md = rs.getString(3);
64             csrName = rs.getString(4);
65             crtName = rs.getString(5);
66             ownerId = rs.getInt(6);
67             this.serial = serial;
68             rs.close();
69         } catch (SQLException e) {
70             e.printStackTrace();
71         }
72     }
73
74     public enum CertificateStatus {
75         /**
76          * This certificate is not in the database, has no id and only exists as
77          * this java object.
78          */
79         DRAFT(),
80         /**
81          * The certificate has been signed. It is stored in the database.
82          * {@link Certificate#cert()} is valid.
83          */
84         ISSUED(),
85
86         /**
87          * The certificate has been revoked.
88          */
89         REVOKED(),
90
91         /**
92          * If this certificate cannot be updated because an error happened in
93          * the signer.
94          */
95         ERROR();
96
97         private CertificateStatus() {}
98
99     }
100
101     public CertificateStatus getStatus() throws SQLException {
102         if (id == 0) {
103             return CertificateStatus.DRAFT;
104         }
105         PreparedStatement searcher = DatabaseConnection.getInstance().prepare("SELECT crt_name, created, revoked, serial FROM emailcerts WHERE id=?");
106         searcher.setInt(1, id);
107         ResultSet rs = searcher.executeQuery();
108         if ( !rs.next()) {
109             throw new IllegalStateException("Certificate not in Database");
110         }
111
112         crtName = rs.getString(1);
113         serial = rs.getString(4);
114         if (rs.getTime(2) == null) {
115             return CertificateStatus.DRAFT;
116         }
117         if (rs.getTime(2) != null && rs.getTime(3) == null) {
118             return CertificateStatus.ISSUED;
119         }
120         return CertificateStatus.REVOKED;
121     }
122
123     public Job issue() throws IOException, SQLException {
124         if (getStatus() != CertificateStatus.DRAFT) {
125             throw new IllegalStateException();
126         }
127         Notary.writeUserAgreement(ownerId, "CCA", "issue certificate", "", true, 0);
128
129         PreparedStatement inserter = DatabaseConnection.getInstance().prepare("INSERT INTO emailcerts SET md=?, subject=?, csr_type=?, crt_name='', memid=?, profile=1");
130         inserter.setString(1, md);
131         inserter.setString(2, dn);
132         inserter.setString(3, csrType.toString());
133         inserter.setInt(4, ownerId);
134         inserter.execute();
135         id = DatabaseConnection.lastInsertId(inserter);
136         File csrFile = KeyStorage.locateCsr(id);
137         csrName = csrFile.getPath();
138         FileOutputStream fos = new FileOutputStream(csrFile);
139         fos.write(csr.getBytes());
140         fos.close();
141
142         // TODO draft to insert SANs
143         PreparedStatement san = DatabaseConnection.getInstance().prepare("INSERT INTO subjectAlternativeNames SET certId=?, contents=?, type=?");
144         san.setInt(1, id);
145         san.setString(2, "<address>");
146         san.setString(3, "email");
147         // san.execute();
148
149         PreparedStatement updater = DatabaseConnection.getInstance().prepare("UPDATE emailcerts SET csr_name=? WHERE id=?");
150         updater.setString(1, csrName);
151         updater.setInt(2, id);
152         updater.execute();
153         return Job.submit(this, JobType.SIGN);
154
155     }
156
157     public Job revoke() throws SQLException {
158         if (getStatus() != CertificateStatus.ISSUED) {
159             throw new IllegalStateException();
160         }
161         return Job.submit(this, JobType.REVOKE);
162
163     }
164
165     public X509Certificate cert() throws IOException, GeneralSecurityException, SQLException {
166         CertificateStatus status = getStatus();
167         if (status != CertificateStatus.ISSUED) {
168             throw new IllegalStateException(status + " is not wanted here.");
169         }
170         InputStream is = null;
171         X509Certificate crt = null;
172         try {
173             is = new FileInputStream(crtName);
174             CertificateFactory cf = CertificateFactory.getInstance("X.509");
175             crt = (X509Certificate) cf.generateCertificate(is);
176         } finally {
177             if (is != null) {
178                 is.close();
179             }
180         }
181         return crt;
182     }
183
184     public Certificate renew() {
185         return null;
186     }
187
188     public int getId() {
189         return id;
190     }
191
192     public String getSerial() {
193         try {
194             getStatus();
195         } catch (SQLException e) {
196             e.printStackTrace();
197         } // poll changes
198         return serial;
199     }
200
201     public String getDistinguishedName() {
202         return dn;
203     }
204
205     public String getMessageDigest() {
206         return md;
207     }
208
209     public int getOwnerId() {
210         return ownerId;
211     }
212
213     public static Certificate getBySerial(String serial) {
214         // TODO caching?
215         try {
216             return new Certificate(serial);
217         } catch (IllegalArgumentException e) {
218
219         }
220         return null;
221     }
222
223 }