1 package org.cacert.gigi;
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;
15 import org.cacert.gigi.database.DatabaseConnection;
16 import org.cacert.gigi.util.KeyStorage;
17 import org.cacert.gigi.util.Notary;
19 public class Certificate {
22 private String serial;
25 private String csrName;
26 private String crtName;
27 private String csr = null;
29 public Certificate(int ownerId, String dn, String md, String csr) {
30 this.ownerId = ownerId;
36 private Certificate(String serial) {
38 PreparedStatement ps = DatabaseConnection.getInstance().prepare(
39 "SELECT id,subject, md, csr_name, crt_name,memid FROM `emailcerts` WHERE serial=?");
40 ps.setString(1, serial);
41 ResultSet rs = ps.executeQuery();
43 throw new IllegalArgumentException("Invalid mid " + serial);
45 this.id = rs.getInt(1);
48 csrName = rs.getString(4);
49 crtName = rs.getString(5);
50 ownerId = rs.getInt(6);
53 } catch (SQLException e) {
58 public enum CertificateStatus {
60 * This certificate is not in the database, has no id and only exists as
65 * The certificate has been written to the database and is waiting for
66 * the signer to sign it.
70 * The certificate has been signed. It is stored in the database.
71 * {@link Certificate#cert()} is valid.
75 * The cetrificate is about to be revoked by the signer bot.
80 * The certificate has been revoked.
85 * If this certificate cannot be updated because an error happened in
90 private boolean unstable;
92 private CertificateStatus(boolean unstable) {
93 this.unstable = unstable;
97 * Checks, iff this certificate stage will be left by signer actions.
99 * @return True, iff this certificate stage will be left by signer
102 public boolean isUnstable() {
108 public CertificateStatus getStatus() throws SQLException {
110 return CertificateStatus.DRAFT;
112 PreparedStatement searcher = DatabaseConnection.getInstance().prepare(
113 "SELECT crt_name, created, revoked, warning, serial FROM emailcerts WHERE id=?");
114 searcher.setInt(1, id);
115 ResultSet rs = searcher.executeQuery();
117 throw new IllegalStateException("Certificate not in Database");
119 if (rs.getInt(4) >= 3) {
120 return CertificateStatus.ERROR;
123 if (rs.getString(2) == null) {
124 return CertificateStatus.SIGNING;
126 crtName = rs.getString(1);
127 serial = rs.getString(5);
128 if (rs.getTime(2) != null && rs.getTime(3) == null) {
129 return CertificateStatus.ISSUED;
131 if (rs.getTime(2) != null && rs.getString(3).equals("1970-01-01 00:00:00.0")) {
132 return CertificateStatus.BEING_REVOKED;
134 return CertificateStatus.REVOKED;
137 public void issue() throws IOException {
139 if (getStatus() != CertificateStatus.DRAFT) {
140 throw new IllegalStateException();
142 Notary.writeUserAgreement(ownerId, "CCA", "issue certificate", "", true, 0);
144 PreparedStatement inserter = DatabaseConnection.getInstance().prepare(
145 "INSERT INTO emailcerts SET md=?, subject=?, coll_found=0, crt_name='', memid=?");
146 inserter.setString(1, md);
147 inserter.setString(2, dn);
148 inserter.setInt(3, ownerId);
150 id = DatabaseConnection.lastInsertId(inserter);
151 File csrFile = KeyStorage.locateCsr(id);
152 csrName = csrFile.getPath();
153 FileOutputStream fos = new FileOutputStream(csrFile);
154 fos.write(csr.getBytes());
157 PreparedStatement updater = DatabaseConnection.getInstance().prepare(
158 "UPDATE emailcerts SET csr_name=? WHERE id=?");
159 updater.setString(1, csrName);
160 updater.setInt(2, id);
162 } catch (SQLException e) {
168 public boolean waitFor(int max) throws SQLException, InterruptedException {
169 long start = System.currentTimeMillis();
170 while (getStatus().isUnstable()) {
171 if (max != 0 && System.currentTimeMillis() - start > max) {
174 Thread.sleep((long) (2000 + Math.random() * 2000));
179 public void revoke() {
181 if (getStatus() != CertificateStatus.ISSUED) {
182 throw new IllegalStateException();
184 PreparedStatement inserter = DatabaseConnection.getInstance().prepare(
185 "UPDATE emailcerts SET revoked = '1970-01-01' WHERE id=?");
186 inserter.setInt(1, id);
188 } catch (SQLException e) {
194 public X509Certificate cert() throws IOException, GeneralSecurityException, SQLException {
195 CertificateStatus status = getStatus();
196 if (status != CertificateStatus.ISSUED) {
197 throw new IllegalStateException(status + " is not wanted here.");
199 InputStream is = null;
200 X509Certificate crt = null;
202 is = new FileInputStream(crtName);
203 CertificateFactory cf = CertificateFactory.getInstance("X.509");
204 crt = (X509Certificate) cf.generateCertificate(is);
213 public Certificate renew() {
221 public String getSerial() {
225 public String getDistinguishedName() {
229 public String getMessageDigest() {
233 public int getOwnerId() {
237 public static Certificate getBySerial(String serial) {
240 return new Certificate(serial);
241 } catch (IllegalArgumentException e) {