]> WPIA git - gigi.git/blob - src/org/cacert/gigi/Certificate.java
9d6d5d8d39f30a1fb36c04aa9fa377454749b5ed
[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.KeyStorage;
17
18 public class Certificate {
19         private int id;
20         private int serial;
21         private String dn;
22         private String md;
23         private String csrName;
24         private String crtName;
25         private String csr = null;
26
27         public Certificate(String dn, String md, String csr) {
28                 this.dn = dn;
29                 this.md = md;
30                 this.csr = csr;
31         }
32
33         public Certificate(int id) {
34                 try {
35                         PreparedStatement ps = DatabaseConnection.getInstance().prepare(
36                                 "SELECT subject, md, csr_name, crt_name FROM `emailcerts` WHERE id=?");
37                         ps.setInt(1, id);
38                         ResultSet rs = ps.executeQuery();
39                         if (!rs.next()) {
40                                 throw new IllegalArgumentException("Invalid mid " + id);
41                         }
42                         this.id = id;
43                         dn = rs.getString(1);
44                         md = rs.getString(2);
45                         csrName = rs.getString(3);
46                         crtName = rs.getString(4);
47                         rs.close();
48                 } catch (SQLException e) {
49                         e.printStackTrace();
50                 }
51         }
52
53         public enum CertificateStatus {
54                 /**
55                  * This certificate is not in the database, has no id and only exists as
56                  * this java object.
57                  */
58                 DRAFT(false),
59                 /**
60                  * The certificate has been written to the database and is waiting for
61                  * the signer to sign it.
62                  */
63                 SIGNING(true),
64                 /**
65                  * The certificate has been signed. It is stored in the database.
66                  * {@link Certificate#cert()} is valid.
67                  */
68                 ISSUED(false),
69                 /**
70                  * The cetrificate is about to be revoked by the signer bot.
71                  */
72                 BEING_REVOKED(true),
73
74                 /**
75                  * The certificate has been revoked.
76                  */
77                 REVOKED(false),
78
79                 /**
80                  * If this certificate cannot be updated because an error happened in
81                  * the signer.
82                  */
83                 ERROR(false);
84
85                 private boolean unstable;
86
87                 private CertificateStatus(boolean unstable) {
88                         this.unstable = unstable;
89                 }
90
91                 /**
92                  * Checks, iff this certificate stage will be left by signer actions.
93                  * 
94                  * @return True, iff this certificate stage will be left by signer
95                  *         actions.
96                  */
97                 public boolean isUnstable() {
98                         return unstable;
99                 }
100
101         }
102
103         public CertificateStatus getStatus() throws SQLException {
104                 if (id == 0) {
105                         return CertificateStatus.DRAFT;
106                 }
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();
111                 if (!rs.next()) {
112                         throw new IllegalStateException("Certificate not in Database");
113                 }
114                 if (rs.getInt(4) >= 3) {
115                         return CertificateStatus.ERROR;
116                 }
117
118                 if (rs.getString(2) == null) {
119                         return CertificateStatus.SIGNING;
120                 }
121                 crtName = rs.getString(1);
122                 System.out.println(crtName);
123                 if (rs.getTime(2) != null && rs.getTime(3) == null) {
124                         return CertificateStatus.ISSUED;
125                 }
126                 if (rs.getTime(2) != null && rs.getString(3).equals("1970-01-01 00:00:00.0")) {
127                         return CertificateStatus.BEING_REVOKED;
128                 }
129                 return CertificateStatus.REVOKED;
130         }
131
132         public void issue() throws IOException {
133                 try {
134                         if (getStatus() != CertificateStatus.DRAFT) {
135                                 throw new IllegalStateException();
136                         }
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);
141                         inserter.execute();
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());
147                         fos.close();
148
149                         PreparedStatement updater = DatabaseConnection.getInstance().prepare(
150                                 "UPDATE emailcerts SET csr_name=? WHERE id=?");
151                         updater.setString(1, csrName);
152                         updater.setInt(2, id);
153                         updater.execute();
154                 } catch (SQLException e) {
155                         e.printStackTrace();
156                 }
157
158         }
159
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) {
164                                 return false;
165                         }
166                         Thread.sleep((long) (2000 + Math.random() * 2000));
167                 }
168                 return true;
169         }
170
171         public void revoke() {
172                 try {
173                         if (getStatus() != CertificateStatus.ISSUED) {
174                                 throw new IllegalStateException();
175                         }
176                         PreparedStatement inserter = DatabaseConnection.getInstance().prepare(
177                                 "UPDATE emailcerts SET revoked = '1970-01-01' WHERE id=?");
178                         inserter.setInt(1, id);
179                         inserter.execute();
180                 } catch (SQLException e) {
181                         e.printStackTrace();
182                 }
183
184         }
185
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.");
190                 }
191                 InputStream is = null;
192                 X509Certificate crt = null;
193                 try {
194                         is = new FileInputStream(crtName);
195                         CertificateFactory cf = CertificateFactory.getInstance("X.509");
196                         crt = (X509Certificate) cf.generateCertificate(is);
197                 } finally {
198                         if (is != null) {
199                                 is.close();
200                         }
201                 }
202                 return crt;
203         }
204
205         public Certificate renew() {
206                 return null;
207         }
208
209         public int getId() {
210                 return id;
211         }
212
213         public int getSerial() {
214                 return serial;
215         }
216
217         public String getDistinguishedName() {
218                 return dn;
219         }
220
221         public String getMessageDigest() {
222                 return md;
223         }
224
225 }