Adding "Error" as Certificate status.
[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         public Certificate(String dn, String md, String csr) {
27                 this.dn = dn;
28                 this.md = md;
29                 this.csr = csr;
30         }
31
32         public enum CertificateStatus {
33                 /**
34                  * This certificate is not in the database, has no id and only exists as
35                  * this java object.
36                  */
37                 DRAFT(false),
38                 /**
39                  * The certificate has been written to the database and is waiting for
40                  * the signer to sign it.
41                  */
42                 SIGNING(true),
43                 /**
44                  * The certificate has been signed. It is stored in the database.
45                  * {@link Certificate#cert()} is valid.
46                  */
47                 ISSUED(false),
48                 /**
49                  * The cetrificate is about to be revoked by the signer bot.
50                  */
51                 BEING_REVOKED(true),
52
53                 /**
54                  * The certificate has been revoked.
55                  */
56                 REVOKED(false),
57
58                 /**
59                  * If this certificate cannot be updated because an error happened in
60                  * the signer.
61                  */
62                 ERROR(false);
63
64                 private boolean unstable;
65
66                 private CertificateStatus(boolean unstable) {
67                         this.unstable = unstable;
68                 }
69                 /**
70                  * Checks, iff this certificate stage will be left by signer actions.
71                  * 
72                  * @return True, iff this certificate stage will be left by signer
73                  *         actions.
74                  */
75                 public boolean isUnstable() {
76                         return unstable;
77                 }
78
79         }
80         public CertificateStatus getStatus() throws SQLException {
81                 if (id == 0) {
82                         return CertificateStatus.DRAFT;
83                 }
84                 PreparedStatement searcher = DatabaseConnection
85                                 .getInstance()
86                                 .prepare(
87                                                 "SELECT crt_name, created, revoked, warning FROM emailcerts WHERE id=?");
88                 searcher.setInt(1, id);
89                 ResultSet rs = searcher.executeQuery();
90                 if (!rs.next()) {
91                         throw new IllegalStateException("Certificate not in Database");
92                 }
93                 if (rs.getInt(4) >= 3) {
94                         return CertificateStatus.ERROR;
95                 }
96
97                 if (rs.getString(2) == null) {
98                         return CertificateStatus.SIGNING;
99                 }
100                 crtName = rs.getString(1);
101                 System.out.println(crtName);
102                 if (rs.getTime(2) != null && rs.getTime(3) == null) {
103                         return CertificateStatus.ISSUED;
104                 }
105                 if (rs.getTime(2) != null
106                                 && rs.getString(3).equals("1970-01-01 00:00:00.0")) {
107                         return CertificateStatus.BEING_REVOKED;
108                 }
109                 return CertificateStatus.REVOKED;
110         }
111
112         public void issue() throws IOException {
113                 try {
114                         if (getStatus() != CertificateStatus.DRAFT) {
115                                 throw new IllegalStateException();
116                         }
117                         PreparedStatement inserter = DatabaseConnection
118                                         .getInstance()
119                                         .prepare(
120                                                         "INSERT INTO emailcerts SET md=?, subject=?, coll_found=0, crt_name=''");
121                         inserter.setString(1, md);
122                         inserter.setString(2, dn);
123                         inserter.execute();
124                         id = DatabaseConnection.lastInsertId(inserter);
125                         File csrFile = KeyStorage.locateCsr(id);
126                         csrName = csrFile.getPath();
127                         FileOutputStream fos = new FileOutputStream(csrFile);
128                         fos.write(csr.getBytes());
129                         fos.close();
130
131                         PreparedStatement updater = DatabaseConnection.getInstance()
132                                         .prepare("UPDATE emailcerts SET csr_name=? WHERE id=?");
133                         updater.setString(1, csrName);
134                         updater.setInt(2, id);
135                         updater.execute();
136                 } catch (SQLException e) {
137                         e.printStackTrace();
138                 }
139
140         }
141         public boolean waitFor(int max) throws SQLException, InterruptedException {
142                 long start = System.currentTimeMillis();
143                 while (getStatus().isUnstable()) {
144                         if (max != 0 && System.currentTimeMillis() - start > max) {
145                                 return false;
146                         }
147                         Thread.sleep((long) (2000 + Math.random() * 2000));
148                 }
149                 return true;
150         }
151         public void revoke() {
152                 try {
153                         if (getStatus() != CertificateStatus.ISSUED) {
154                                 throw new IllegalStateException();
155                         }
156                         PreparedStatement inserter = DatabaseConnection
157                                         .getInstance()
158                                         .prepare(
159                                                         "UPDATE emailcerts SET revoked = '1970-01-01' WHERE id=?");
160                         inserter.setInt(1, id);
161                         inserter.execute();
162                 } catch (SQLException e) {
163                         e.printStackTrace();
164                 }
165
166         }
167
168         public X509Certificate cert() throws IOException, GeneralSecurityException,
169                         SQLException {
170                 CertificateStatus status = getStatus();
171                 if (status != CertificateStatus.ISSUED) {
172                         throw new IllegalStateException(status + " is not wanted here.");
173                 }
174                 InputStream is = null;
175                 X509Certificate crt = null;
176                 try {
177                         is = new FileInputStream(crtName);
178                         CertificateFactory cf = CertificateFactory.getInstance("X.509");
179                         crt = (X509Certificate) cf.generateCertificate(is);
180                 } finally {
181                         if (is != null) {
182                                 is.close();
183                         }
184                 }
185                 return crt;
186         }
187         public Certificate renew() {
188                 return null;
189         }
190         public int getId() {
191                 return id;
192         }
193         public int getSerial() {
194                 return serial;
195         }
196         public String getDistinguishedName() {
197                 return dn;
198         }
199         public String getMessageDigest() {
200                 return md;
201         }
202
203 }