[Keys] a certificate structure that looks like the planned future.
[gigi.git] / util / org / cacert / gigi / util / SimpleSigner.java
1 package org.cacert.gigi.util;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.io.FileReader;
7 import java.io.IOException;
8 import java.io.InputStream;
9 import java.io.InputStreamReader;
10 import java.io.PrintWriter;
11 import java.math.BigInteger;
12 import java.security.GeneralSecurityException;
13 import java.security.cert.CertificateFactory;
14 import java.security.cert.X509Certificate;
15 import java.sql.PreparedStatement;
16 import java.sql.ResultSet;
17 import java.sql.SQLException;
18 import java.util.Arrays;
19 import java.util.Properties;
20
21 import org.cacert.gigi.Certificate.CSRType;
22 import org.cacert.gigi.database.DatabaseConnection;
23
24 public class SimpleSigner {
25
26     private static PreparedStatement warnMail;
27
28     private static PreparedStatement updateMail;
29
30     private static PreparedStatement readyCerts;
31
32     private static PreparedStatement getSANSs;
33
34     private static PreparedStatement revoke;
35
36     private static PreparedStatement revokeCompleted;
37
38     private static PreparedStatement finishJob;
39
40     private static boolean running = true;
41
42     private static Thread runner;
43
44     public static void main(String[] args) throws IOException, SQLException, InterruptedException {
45         Properties p = new Properties();
46         p.load(new FileReader("config/gigi.properties"));
47         DatabaseConnection.init(p);
48
49         runSigner();
50     }
51
52     public synchronized static void stopSigner() throws InterruptedException {
53         if (runner == null) {
54             throw new IllegalStateException("already stopped");
55         }
56         running = false;
57         runner.interrupt();
58         runner.join();
59         runner = null;
60     }
61
62     public synchronized static void runSigner() throws SQLException, IOException, InterruptedException {
63         if (runner != null) {
64             throw new IllegalStateException("already running");
65         }
66         running = true;
67         readyCerts = DatabaseConnection.getInstance().prepare("SELECT certs.id AS id, certs.csr_name, certs.subject, jobs.id AS jobid, csr_type, md, keyUsage, extendedKeyUsage FROM jobs " + //
68                 "INNER JOIN certs ON certs.id=jobs.targetId " + //
69                 "INNER JOIN profiles ON profiles.id=certs.profile " + //
70                 "WHERE jobs.state='open' "//
71                 + "AND task='sign'");
72
73         getSANSs = DatabaseConnection.getInstance().prepare("SELECT contents, type FROM subjectAlternativeNames " + //
74                 "WHERE certId=?");
75
76         updateMail = DatabaseConnection.getInstance().prepare("UPDATE certs SET crt_name=?," + " created=NOW(), serial=? WHERE id=?");
77         warnMail = DatabaseConnection.getInstance().prepare("UPDATE jobs SET warning=warning+1, state=IF(warning<3, 'open','error') WHERE id=?");
78
79         revoke = DatabaseConnection.getInstance().prepare("SELECT certs.id, certs.csr_name,jobs.id FROM jobs INNER JOIN certs ON jobs.targetId=certs.id" + " WHERE jobs.state='open' AND task='revoke'");
80         revokeCompleted = DatabaseConnection.getInstance().prepare("UPDATE certs SET revoked=NOW() WHERE id=?");
81
82         finishJob = DatabaseConnection.getInstance().prepare("UPDATE jobs SET state='done' WHERE id=?");
83
84         runner = new Thread() {
85
86             @Override
87             public void run() {
88                 work();
89             }
90
91         };
92         runner.start();
93     }
94
95     private static void work() {
96         try {
97             gencrl();
98         } catch (IOException e2) {
99             e2.printStackTrace();
100         } catch (InterruptedException e2) {
101             e2.printStackTrace();
102         }
103         while (running) {
104             try {
105                 signCertificates();
106                 revokeCertificates();
107                 Thread.sleep(5000);
108             } catch (IOException e) {
109                 e.printStackTrace();
110             } catch (SQLException e) {
111                 e.printStackTrace();
112             } catch (InterruptedException e1) {
113             }
114         }
115     }
116
117     private static void revokeCertificates() throws SQLException, IOException, InterruptedException {
118         ResultSet rs = revoke.executeQuery();
119         boolean worked = false;
120         while (rs.next()) {
121             int id = rs.getInt(1);
122             File crt = KeyStorage.locateCrt(id);
123             String[] call = new String[] {
124                     "openssl", "ca",//
125                     "-cert",
126                     "../unassured.crt",//
127                     "-keyfile",
128                     "../unassured.key",//
129                     "-revoke",
130                     "../../" + crt.getPath(),//
131                     "-batch",//
132                     "-config",
133                     "../selfsign.config"
134
135             };
136             Process p1 = Runtime.getRuntime().exec(call, null, new File("keys/unassured.ca"));
137             System.out.println("revoking: " + crt.getPath());
138             if (p1.waitFor() == 0) {
139                 worked = true;
140                 revokeCompleted.setInt(1, id);
141                 revokeCompleted.execute();
142                 finishJob.setInt(1, rs.getInt(3));
143                 finishJob.execute();
144             } else {
145                 System.out.println("Failed");
146             }
147         }
148         if (worked) {
149             gencrl();
150         }
151     }
152
153     private static void gencrl() throws IOException, InterruptedException {
154         String[] call = new String[] {
155                 "openssl", "ca",//
156                 "-cert",
157                 "../unassured.crt",//
158                 "-keyfile",
159                 "../unassured.key",//
160                 "-gencrl",//
161                 "-crlhours",//
162                 "12",//
163                 "-out",
164                 "../unassured.crl",//
165                 "-config",
166                 "../selfsign.config"
167
168         };
169         Process p1 = Runtime.getRuntime().exec(call, null, new File("keys/unassured.ca"));
170         if (p1.waitFor() != 0) {
171             System.out.println("Error while generating crl.");
172         }
173     }
174
175     private static int counter = 0;
176
177     private static void signCertificates() throws SQLException, IOException, InterruptedException {
178         ResultSet rs = readyCerts.executeQuery();
179         while (rs.next()) {
180             String csrname = rs.getString("csr_name");
181             System.out.println("sign: " + csrname);
182             int id = rs.getInt("id");
183             String csrType = rs.getString("csr_type");
184             CSRType ct = CSRType.valueOf(csrType);
185             File crt = KeyStorage.locateCrt(id);
186
187             String keyUsage = rs.getString("keyUsage");
188             String ekeyUsage = rs.getString("extendedKeyUsage");
189             getSANSs.setInt(1, id);
190             ResultSet san = getSANSs.executeQuery();
191
192             File f = new File("keys", "SANFile" + System.currentTimeMillis() + (counter++) + ".cfg");
193             PrintWriter cfg = new PrintWriter(f);
194             boolean first = true;
195             while (san.next()) {
196                 if ( !first) {
197                     cfg.print(", ");
198                 } else {
199                     cfg.print("subjectAltName=");
200                 }
201                 first = false;
202                 cfg.print(san.getString("type"));
203                 cfg.print(":");
204                 cfg.print(san.getString("contents"));
205             }
206             cfg.println();
207             cfg.println("keyUsage=" + keyUsage);
208             cfg.println("extendedKeyUsage=" + ekeyUsage);
209             cfg.close();
210
211             String[] call = new String[] {
212                     "openssl", "ca",//
213                     "-in",
214                     "../../" + csrname,//
215                     "-cert",
216                     "../unassured.crt",//
217                     "-keyfile",
218                     "../unassured.key",//
219                     "-out",
220                     "../../" + crt.getPath(),//
221                     "-days",
222                     "356",//
223                     "-batch",//
224                     "-md",
225                     rs.getString("md"),//
226                     "-extfile",
227                     "../" + f.getName(),//
228
229                     "-subj",
230                     rs.getString("subject"),//
231                     "-config",
232                     "../selfsign.config"//
233
234             };
235             if (ct == CSRType.SPKAC) {
236                 call[2] = "-spkac";
237             }
238             Process p1 = Runtime.getRuntime().exec(call, null, new File("keys/unassured.ca"));
239
240             int waitFor = p1.waitFor();
241             f.delete();
242             if (waitFor == 0) {
243                 try (InputStream is = new FileInputStream(crt)) {
244                     CertificateFactory cf = CertificateFactory.getInstance("X.509");
245                     X509Certificate crtp = (X509Certificate) cf.generateCertificate(is);
246                     BigInteger serial = crtp.getSerialNumber();
247                     updateMail.setString(1, crt.getPath());
248                     updateMail.setString(2, serial.toString(16));
249                     updateMail.setInt(3, id);
250                     updateMail.execute();
251
252                     finishJob.setInt(1, rs.getInt("jobid"));
253                     finishJob.execute();
254                     System.out.println("signed: " + id);
255                     continue;
256                 } catch (GeneralSecurityException e) {
257                     e.printStackTrace();
258                 }
259                 System.out.println("ERROR Afterwards: " + id);
260                 warnMail.setInt(1, rs.getInt("jobid"));
261                 warnMail.execute();
262             } else {
263                 BufferedReader br = new BufferedReader(new InputStreamReader(p1.getErrorStream()));
264                 String s;
265                 while ((s = br.readLine()) != null) {
266                     System.out.println(s);
267                 }
268                 System.out.println(Arrays.toString(call));
269                 System.out.println("ERROR: " + id);
270                 warnMail.setInt(1, rs.getInt("jobid"));
271                 warnMail.execute();
272             }
273
274         }
275         rs.close();
276     }
277 }