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