]> WPIA git - gigi.git/blob - util/org/cacert/gigi/util/SimpleSigner.java
Implement fixed-time signing.
[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.util.Date;
16 import java.sql.PreparedStatement;
17 import java.sql.ResultSet;
18 import java.sql.SQLException;
19 import java.text.ParseException;
20 import java.text.SimpleDateFormat;
21 import java.util.Calendar;
22 import java.util.Properties;
23 import java.util.TimeZone;
24
25 import org.cacert.gigi.Certificate.CSRType;
26 import org.cacert.gigi.database.DatabaseConnection;
27 import org.cacert.gigi.output.CertificateValiditySelector;
28
29 public class SimpleSigner {
30
31     private static PreparedStatement warnMail;
32
33     private static PreparedStatement updateMail;
34
35     private static PreparedStatement readyCerts;
36
37     private static PreparedStatement getSANSs;
38
39     private static PreparedStatement revoke;
40
41     private static PreparedStatement revokeCompleted;
42
43     private static PreparedStatement finishJob;
44
45     private static boolean running = true;
46
47     private static Thread runner;
48
49     private static SimpleDateFormat sdf = new SimpleDateFormat("YYMMddHHmmss'Z'");
50     static {
51         sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
52     }
53
54     public static void main(String[] args) throws IOException, SQLException, InterruptedException {
55         Properties p = new Properties();
56         p.load(new FileReader("config/gigi.properties"));
57         DatabaseConnection.init(p);
58
59         runSigner();
60     }
61
62     public synchronized static void stopSigner() throws InterruptedException {
63         if (runner == null) {
64             throw new IllegalStateException("already stopped");
65         }
66         running = false;
67         runner.interrupt();
68         runner.join();
69         runner = null;
70     }
71
72     public synchronized static void runSigner() throws SQLException, IOException, InterruptedException {
73         if (runner != null) {
74             throw new IllegalStateException("already running");
75         }
76         running = true;
77         readyCerts = DatabaseConnection.getInstance().prepare("SELECT certs.id AS id, certs.csr_name, certs.subject, jobs.id AS jobid, csr_type, md, keyUsage, extendedKeyUsage, executeFrom, executeTo FROM jobs " + //
78                 "INNER JOIN certs ON certs.id=jobs.targetId " + //
79                 "INNER JOIN profiles ON profiles.id=certs.profile " + //
80                 "WHERE jobs.state='open' "//
81                 + "AND task='sign'");
82
83         getSANSs = DatabaseConnection.getInstance().prepare("SELECT contents, type FROM subjectAlternativeNames " + //
84                 "WHERE certId=?");
85
86         updateMail = DatabaseConnection.getInstance().prepare("UPDATE certs SET crt_name=?," + " created=NOW(), serial=? WHERE id=?");
87         warnMail = DatabaseConnection.getInstance().prepare("UPDATE jobs SET warning=warning+1, state=IF(warning<3, 'open','error') WHERE id=?");
88
89         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'");
90         revokeCompleted = DatabaseConnection.getInstance().prepare("UPDATE certs SET revoked=NOW() WHERE id=?");
91
92         finishJob = DatabaseConnection.getInstance().prepare("UPDATE jobs SET state='done' WHERE id=?");
93
94         runner = new Thread() {
95
96             @Override
97             public void run() {
98                 work();
99             }
100
101         };
102         runner.start();
103     }
104
105     private static void work() {
106         try {
107             gencrl();
108         } catch (IOException e2) {
109             e2.printStackTrace();
110         } catch (InterruptedException e2) {
111             e2.printStackTrace();
112         }
113         while (running) {
114             try {
115                 signCertificates();
116                 revokeCertificates();
117                 Thread.sleep(5000);
118             } catch (IOException e) {
119                 e.printStackTrace();
120             } catch (SQLException e) {
121                 e.printStackTrace();
122             } catch (InterruptedException e1) {
123             }
124         }
125     }
126
127     private static void revokeCertificates() throws SQLException, IOException, InterruptedException {
128         ResultSet rs = revoke.executeQuery();
129         boolean worked = false;
130         while (rs.next()) {
131             int id = rs.getInt(1);
132             File crt = KeyStorage.locateCrt(id);
133             String[] call = new String[] {
134                     "openssl", "ca",//
135                     "-cert",
136                     "../unassured.crt",//
137                     "-keyfile",
138                     "../unassured.key",//
139                     "-revoke",
140                     "../../" + crt.getPath(),//
141                     "-batch",//
142                     "-config",
143                     "../selfsign.config"
144
145             };
146             Process p1 = Runtime.getRuntime().exec(call, null, new File("keys/unassured.ca"));
147             System.out.println("revoking: " + crt.getPath());
148             if (p1.waitFor() == 0) {
149                 worked = true;
150                 revokeCompleted.setInt(1, id);
151                 revokeCompleted.execute();
152                 finishJob.setInt(1, rs.getInt(3));
153                 finishJob.execute();
154             } else {
155                 System.out.println("Failed");
156             }
157         }
158         if (worked) {
159             gencrl();
160         }
161     }
162
163     private static void gencrl() throws IOException, InterruptedException {
164         String[] call = new String[] {
165                 "openssl", "ca",//
166                 "-cert",
167                 "../unassured.crt",//
168                 "-keyfile",
169                 "../unassured.key",//
170                 "-gencrl",//
171                 "-crlhours",//
172                 "12",//
173                 "-out",
174                 "../unassured.crl",//
175                 "-config",
176                 "../selfsign.config"
177
178         };
179         Process p1 = Runtime.getRuntime().exec(call, null, new File("keys/unassured.ca"));
180         if (p1.waitFor() != 0) {
181             System.out.println("Error while generating crl.");
182         }
183     }
184
185     private static int counter = 0;
186
187     private static void signCertificates() throws SQLException {
188         ResultSet rs = readyCerts.executeQuery();
189         while (rs.next()) {
190             String csrname = rs.getString("csr_name");
191             int id = rs.getInt("id");
192             System.out.println("sign: " + csrname);
193             try {
194                 String csrType = rs.getString("csr_type");
195                 CSRType ct = CSRType.valueOf(csrType);
196                 File crt = KeyStorage.locateCrt(id);
197
198                 String keyUsage = rs.getString("keyUsage");
199                 String ekeyUsage = rs.getString("extendedKeyUsage");
200                 java.sql.Date from = rs.getDate("executeFrom");
201                 String length = rs.getString("executeTo");
202                 Date fromDate;
203                 Date toDate;
204                 if (from == null) {
205                     fromDate = new Date(System.currentTimeMillis());
206                 } else {
207                     fromDate = new Date(from.getTime());
208                 }
209                 if (length.endsWith("m") || length.endsWith("y")) {
210                     String num = length.substring(0, length.length() - 1);
211                     int inter = Integer.parseInt(num);
212                     Calendar c = Calendar.getInstance();
213                     c.setTimeZone(TimeZone.getTimeZone("UTC"));
214                     c.setTime(fromDate);
215                     if (length.endsWith("m")) {
216                         c.add(Calendar.MONTH, inter);
217                     } else {
218                         c.add(Calendar.YEAR, inter);
219                     }
220                     toDate = c.getTime();
221                 } else {
222                     toDate = CertificateValiditySelector.getDateFormat().parse(length);
223                 }
224                 System.out.println(from);
225                 System.out.println(sdf.format(fromDate));
226
227                 getSANSs.setInt(1, id);
228                 ResultSet san = getSANSs.executeQuery();
229
230                 File f = new File("keys", "SANFile" + System.currentTimeMillis() + (counter++) + ".cfg");
231                 PrintWriter cfg = new PrintWriter(f);
232                 boolean first = true;
233                 while (san.next()) {
234                     if ( !first) {
235                         cfg.print(", ");
236                     } else {
237                         cfg.print("subjectAltName=");
238                     }
239                     first = false;
240                     cfg.print(san.getString("type"));
241                     cfg.print(":");
242                     cfg.print(san.getString("contents"));
243                 }
244                 cfg.println();
245                 cfg.println("keyUsage=" + keyUsage);
246                 cfg.println("extendedKeyUsage=" + ekeyUsage);
247                 cfg.close();
248
249                 String[] call = new String[] {
250                         "openssl", "ca",//
251                         "-in",
252                         "../../" + csrname,//
253                         "-cert",
254                         "../unassured.crt",//
255                         "-keyfile",
256                         "../unassured.key",//
257                         "-out",
258                         "../../" + crt.getPath(),//
259                         "-utf8",
260                         "-startdate",
261                         sdf.format(fromDate),//
262                         "-enddate",
263                         sdf.format(toDate),//
264                         "-batch",//
265                         "-md",
266                         rs.getString("md"),//
267                         "-extfile",
268                         "../" + f.getName(),//
269
270                         "-subj",
271                         rs.getString("subject"),//
272                         "-config",
273                         "../selfsign.config"//
274
275                 };
276                 if (ct == CSRType.SPKAC) {
277                     call[2] = "-spkac";
278                 }
279                 Process p1 = Runtime.getRuntime().exec(call, null, new File("keys/unassured.ca"));
280
281                 int waitFor = p1.waitFor();
282                 f.delete();
283                 if (waitFor == 0) {
284                     try (InputStream is = new FileInputStream(crt)) {
285                         CertificateFactory cf = CertificateFactory.getInstance("X.509");
286                         X509Certificate crtp = (X509Certificate) cf.generateCertificate(is);
287                         BigInteger serial = crtp.getSerialNumber();
288                         updateMail.setString(1, crt.getPath());
289                         updateMail.setString(2, serial.toString(16));
290                         updateMail.setInt(3, id);
291                         updateMail.execute();
292
293                         finishJob.setInt(1, rs.getInt("jobid"));
294                         finishJob.execute();
295                         System.out.println("signed: " + id);
296                         continue;
297                     }
298                 } else {
299                     BufferedReader br = new BufferedReader(new InputStreamReader(p1.getErrorStream()));
300                     String s;
301                     while ((s = br.readLine()) != null) {
302                         System.out.println(s);
303                     }
304                 }
305             } catch (GeneralSecurityException e) {
306                 e.printStackTrace();
307             } catch (IOException e) {
308                 e.printStackTrace();
309             } catch (SQLException e) {
310                 e.printStackTrace();
311             } catch (ParseException e) {
312                 e.printStackTrace();
313             } catch (InterruptedException e1) {
314                 e1.printStackTrace();
315             }
316             System.out.println("Error with: " + id);
317             warnMail.setInt(1, rs.getInt("jobid"));
318             warnMail.execute();
319
320         }
321         rs.close();
322     }
323 }