]> WPIA git - gigi.git/blob - src/org/cacert/gigi/Certificate.java
Implement serial based retrival and certificate access control.
[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                 System.out.println(crtName);
127                 if (rs.getTime(2) != null && rs.getTime(3) == null) {
128                         return CertificateStatus.ISSUED;
129                 }
130                 if (rs.getTime(2) != null && rs.getString(3).equals("1970-01-01 00:00:00.0")) {
131                         return CertificateStatus.BEING_REVOKED;
132                 }
133                 return CertificateStatus.REVOKED;
134         }
135
136         public void issue() throws IOException {
137                 try {
138                         if (getStatus() != CertificateStatus.DRAFT) {
139                                 throw new IllegalStateException();
140                         }
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);
146                         inserter.execute();
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());
152                         fos.close();
153
154                         PreparedStatement updater = DatabaseConnection.getInstance().prepare(
155                                 "UPDATE emailcerts SET csr_name=? WHERE id=?");
156                         updater.setString(1, csrName);
157                         updater.setInt(2, id);
158                         updater.execute();
159                 } catch (SQLException e) {
160                         e.printStackTrace();
161                 }
162
163         }
164
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) {
169                                 return false;
170                         }
171                         Thread.sleep((long) (2000 + Math.random() * 2000));
172                 }
173                 return true;
174         }
175
176         public void revoke() {
177                 try {
178                         if (getStatus() != CertificateStatus.ISSUED) {
179                                 throw new IllegalStateException();
180                         }
181                         PreparedStatement inserter = DatabaseConnection.getInstance().prepare(
182                                 "UPDATE emailcerts SET revoked = '1970-01-01' WHERE id=?");
183                         inserter.setInt(1, id);
184                         inserter.execute();
185                 } catch (SQLException e) {
186                         e.printStackTrace();
187                 }
188
189         }
190
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.");
195                 }
196                 InputStream is = null;
197                 X509Certificate crt = null;
198                 try {
199                         is = new FileInputStream(crtName);
200                         CertificateFactory cf = CertificateFactory.getInstance("X.509");
201                         crt = (X509Certificate) cf.generateCertificate(is);
202                 } finally {
203                         if (is != null) {
204                                 is.close();
205                         }
206                 }
207                 return crt;
208         }
209
210         public Certificate renew() {
211                 return null;
212         }
213
214         public int getId() {
215                 return id;
216         }
217
218         public int getSerial() {
219                 return serial;
220         }
221
222         public String getDistinguishedName() {
223                 return dn;
224         }
225
226         public String getMessageDigest() {
227                 return md;
228         }
229
230         public int getOwnerId() {
231                 return ownerId;
232         }
233
234 }