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 {
23 private String csrName;
24 private String crtName;
25 private String csr = null;
27 public Certificate(String dn, String md, String csr) {
33 public Certificate(int id) {
35 PreparedStatement ps = DatabaseConnection.getInstance().prepare(
36 "SELECT subject, md, csr_name, crt_name FROM `emailcerts` WHERE id=?");
38 ResultSet rs = ps.executeQuery();
40 throw new IllegalArgumentException("Invalid mid " + id);
45 csrName = rs.getString(3);
46 crtName = rs.getString(4);
48 } catch (SQLException e) {
53 public enum CertificateStatus {
55 * This certificate is not in the database, has no id and only exists as
60 * The certificate has been written to the database and is waiting for
61 * the signer to sign it.
65 * The certificate has been signed. It is stored in the database.
66 * {@link Certificate#cert()} is valid.
70 * The cetrificate is about to be revoked by the signer bot.
75 * The certificate has been revoked.
80 * If this certificate cannot be updated because an error happened in
85 private boolean unstable;
87 private CertificateStatus(boolean unstable) {
88 this.unstable = unstable;
92 * Checks, iff this certificate stage will be left by signer actions.
94 * @return True, iff this certificate stage will be left by signer
97 public boolean isUnstable() {
103 public CertificateStatus getStatus() throws SQLException {
105 return CertificateStatus.DRAFT;
107 PreparedStatement searcher = DatabaseConnection.getInstance().prepare(
108 "SELECT crt_name, created, revoked, warning FROM emailcerts WHERE id=?");
109 searcher.setInt(1, id);
110 ResultSet rs = searcher.executeQuery();
112 throw new IllegalStateException("Certificate not in Database");
114 if (rs.getInt(4) >= 3) {
115 return CertificateStatus.ERROR;
118 if (rs.getString(2) == null) {
119 return CertificateStatus.SIGNING;
121 crtName = rs.getString(1);
122 System.out.println(crtName);
123 if (rs.getTime(2) != null && rs.getTime(3) == null) {
124 return CertificateStatus.ISSUED;
126 if (rs.getTime(2) != null && rs.getString(3).equals("1970-01-01 00:00:00.0")) {
127 return CertificateStatus.BEING_REVOKED;
129 return CertificateStatus.REVOKED;
132 public void issue() throws IOException {
134 if (getStatus() != CertificateStatus.DRAFT) {
135 throw new IllegalStateException();
137 PreparedStatement inserter = DatabaseConnection.getInstance().prepare(
138 "INSERT INTO emailcerts SET md=?, subject=?, coll_found=0, crt_name=''");
139 inserter.setString(1, md);
140 inserter.setString(2, dn);
142 id = DatabaseConnection.lastInsertId(inserter);
143 File csrFile = KeyStorage.locateCsr(id);
144 csrName = csrFile.getPath();
145 FileOutputStream fos = new FileOutputStream(csrFile);
146 fos.write(csr.getBytes());
149 PreparedStatement updater = DatabaseConnection.getInstance().prepare(
150 "UPDATE emailcerts SET csr_name=? WHERE id=?");
151 updater.setString(1, csrName);
152 updater.setInt(2, id);
154 } catch (SQLException e) {
160 public boolean waitFor(int max) throws SQLException, InterruptedException {
161 long start = System.currentTimeMillis();
162 while (getStatus().isUnstable()) {
163 if (max != 0 && System.currentTimeMillis() - start > max) {
166 Thread.sleep((long) (2000 + Math.random() * 2000));
171 public void revoke() {
173 if (getStatus() != CertificateStatus.ISSUED) {
174 throw new IllegalStateException();
176 PreparedStatement inserter = DatabaseConnection.getInstance().prepare(
177 "UPDATE emailcerts SET revoked = '1970-01-01' WHERE id=?");
178 inserter.setInt(1, id);
180 } catch (SQLException e) {
186 public X509Certificate cert() throws IOException, GeneralSecurityException, SQLException {
187 CertificateStatus status = getStatus();
188 if (status != CertificateStatus.ISSUED) {
189 throw new IllegalStateException(status + " is not wanted here.");
191 InputStream is = null;
192 X509Certificate crt = null;
194 is = new FileInputStream(crtName);
195 CertificateFactory cf = CertificateFactory.getInstance("X.509");
196 crt = (X509Certificate) cf.generateCertificate(is);
205 public Certificate renew() {
213 public int getSerial() {
217 public String getDistinguishedName() {
221 public String getMessageDigest() {