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;
18 public class Certificate {
24 private String csrName;
25 private String crtName;
26 private String csr = null;
28 public Certificate(int ownerId, String dn, String md, String csr) {
29 this.ownerId = ownerId;
35 public Certificate(int id) {
37 PreparedStatement ps = DatabaseConnection.getInstance().prepare(
38 "SELECT id,subject, md, csr_name, crt_name,memid FROM `emailcerts` WHERE serial=?");
40 ResultSet rs = ps.executeQuery();
42 throw new IllegalArgumentException("Invalid mid " + id);
44 this.id = rs.getInt(1);
47 csrName = rs.getString(4);
48 crtName = rs.getString(5);
49 ownerId = rs.getInt(6);
52 } catch (SQLException e) {
57 public enum CertificateStatus {
59 * This certificate is not in the database, has no id and only exists as
64 * The certificate has been written to the database and is waiting for
65 * the signer to sign it.
69 * The certificate has been signed. It is stored in the database.
70 * {@link Certificate#cert()} is valid.
74 * The cetrificate is about to be revoked by the signer bot.
79 * The certificate has been revoked.
84 * If this certificate cannot be updated because an error happened in
89 private boolean unstable;
91 private CertificateStatus(boolean unstable) {
92 this.unstable = unstable;
96 * Checks, iff this certificate stage will be left by signer actions.
98 * @return True, iff this certificate stage will be left by signer
101 public boolean isUnstable() {
107 public CertificateStatus getStatus() throws SQLException {
109 return CertificateStatus.DRAFT;
111 PreparedStatement searcher = DatabaseConnection.getInstance().prepare(
112 "SELECT crt_name, created, revoked, warning FROM emailcerts WHERE id=?");
113 searcher.setInt(1, id);
114 ResultSet rs = searcher.executeQuery();
116 throw new IllegalStateException("Certificate not in Database");
118 if (rs.getInt(4) >= 3) {
119 return CertificateStatus.ERROR;
122 if (rs.getString(2) == null) {
123 return CertificateStatus.SIGNING;
125 crtName = rs.getString(1);
126 System.out.println(crtName);
127 if (rs.getTime(2) != null && rs.getTime(3) == null) {
128 return CertificateStatus.ISSUED;
130 if (rs.getTime(2) != null && rs.getString(3).equals("1970-01-01 00:00:00.0")) {
131 return CertificateStatus.BEING_REVOKED;
133 return CertificateStatus.REVOKED;
136 public void issue() throws IOException {
138 if (getStatus() != CertificateStatus.DRAFT) {
139 throw new IllegalStateException();
141 PreparedStatement inserter = DatabaseConnection.getInstance().prepare(
142 "INSERT INTO emailcerts SET md=?, subject=?, coll_found=0, crt_name='', memid=?");
143 inserter.setString(1, md);
144 inserter.setString(2, dn);
145 inserter.setInt(3, ownerId);
147 id = DatabaseConnection.lastInsertId(inserter);
148 File csrFile = KeyStorage.locateCsr(id);
149 csrName = csrFile.getPath();
150 FileOutputStream fos = new FileOutputStream(csrFile);
151 fos.write(csr.getBytes());
154 PreparedStatement updater = DatabaseConnection.getInstance().prepare(
155 "UPDATE emailcerts SET csr_name=? WHERE id=?");
156 updater.setString(1, csrName);
157 updater.setInt(2, id);
159 } catch (SQLException e) {
165 public boolean waitFor(int max) throws SQLException, InterruptedException {
166 long start = System.currentTimeMillis();
167 while (getStatus().isUnstable()) {
168 if (max != 0 && System.currentTimeMillis() - start > max) {
171 Thread.sleep((long) (2000 + Math.random() * 2000));
176 public void revoke() {
178 if (getStatus() != CertificateStatus.ISSUED) {
179 throw new IllegalStateException();
181 PreparedStatement inserter = DatabaseConnection.getInstance().prepare(
182 "UPDATE emailcerts SET revoked = '1970-01-01' WHERE id=?");
183 inserter.setInt(1, id);
185 } catch (SQLException e) {
191 public X509Certificate cert() throws IOException, GeneralSecurityException, SQLException {
192 CertificateStatus status = getStatus();
193 if (status != CertificateStatus.ISSUED) {
194 throw new IllegalStateException(status + " is not wanted here.");
196 InputStream is = null;
197 X509Certificate crt = null;
199 is = new FileInputStream(crtName);
200 CertificateFactory cf = CertificateFactory.getInstance("X.509");
201 crt = (X509Certificate) cf.generateCertificate(is);
210 public Certificate renew() {
218 public int getSerial() {
222 public String getDistinguishedName() {
226 public String getMessageDigest() {
230 public int getOwnerId() {