1 package org.cacert.gigi.util;
3 import java.io.BufferedReader;
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.sql.Timestamp;
20 import java.text.ParseException;
21 import java.text.SimpleDateFormat;
22 import java.util.Calendar;
23 import java.util.Properties;
24 import java.util.TimeZone;
26 import org.cacert.gigi.Certificate.CSRType;
27 import org.cacert.gigi.database.DatabaseConnection;
28 import org.cacert.gigi.output.CertificateValiditySelector;
30 public class SimpleSigner {
32 private static PreparedStatement warnMail;
34 private static PreparedStatement updateMail;
36 private static PreparedStatement readyCerts;
38 private static PreparedStatement getSANSs;
40 private static PreparedStatement revoke;
42 private static PreparedStatement revokeCompleted;
44 private static PreparedStatement finishJob;
46 private static boolean running = true;
48 private static Thread runner;
50 private static SimpleDateFormat sdf = new SimpleDateFormat("YYMMddHHmmss'Z'");
53 TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
54 sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
57 public static void main(String[] args) throws IOException, SQLException, InterruptedException {
58 Properties p = new Properties();
59 p.load(new FileReader("config/gigi.properties"));
60 DatabaseConnection.init(p);
65 public synchronized static void stopSigner() throws InterruptedException {
67 throw new IllegalStateException("already stopped");
75 public synchronized static void runSigner() throws SQLException, IOException, InterruptedException {
77 throw new IllegalStateException("already running");
80 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, rootcert FROM jobs " + //
81 "INNER JOIN certs ON certs.id=jobs.targetId " + //
82 "INNER JOIN profiles ON profiles.id=certs.profile " + //
83 "WHERE jobs.state='open' "//
86 getSANSs = DatabaseConnection.getInstance().prepare("SELECT contents, type FROM subjectAlternativeNames " + //
89 updateMail = DatabaseConnection.getInstance().prepare("UPDATE certs SET crt_name=?," + " created=NOW(), serial=? WHERE id=?");
90 warnMail = DatabaseConnection.getInstance().prepare("UPDATE jobs SET warning=warning+1, state=IF(warning<3, 'open','error') WHERE id=?");
92 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'");
93 revokeCompleted = DatabaseConnection.getInstance().prepare("UPDATE certs SET revoked=NOW() WHERE id=?");
95 finishJob = DatabaseConnection.getInstance().prepare("UPDATE jobs SET state='done' WHERE id=?");
97 runner = new Thread() {
108 private static void work() {
111 } catch (IOException e2) {
112 e2.printStackTrace();
113 } catch (InterruptedException e2) {
114 e2.printStackTrace();
119 revokeCertificates();
121 } catch (IOException e) {
123 } catch (SQLException e) {
125 } catch (InterruptedException e1) {
130 private static void revokeCertificates() throws SQLException, IOException, InterruptedException {
131 ResultSet rs = revoke.executeQuery();
132 boolean worked = false;
134 int id = rs.getInt(1);
135 File crt = KeyStorage.locateCrt(id);
136 String[] call = new String[] {
139 "../unassured.crt",//
141 "../unassured.key",//
143 "../../" + crt.getPath(),//
149 Process p1 = Runtime.getRuntime().exec(call, null, new File("keys/unassured.ca"));
150 System.out.println("revoking: " + crt.getPath());
151 if (p1.waitFor() == 0) {
153 revokeCompleted.setInt(1, id);
154 revokeCompleted.execute();
155 finishJob.setInt(1, rs.getInt(3));
158 System.out.println("Failed");
166 private static void gencrl() throws IOException, InterruptedException {
167 String[] call = new String[] {
170 "../unassured.crt",//
172 "../unassured.key",//
177 "../unassured.crl",//
182 Process p1 = Runtime.getRuntime().exec(call, null, new File("keys/unassured.ca"));
183 if (p1.waitFor() != 0) {
184 System.out.println("Error while generating crl.");
188 private static int counter = 0;
190 private static void signCertificates() throws SQLException {
191 ResultSet rs = readyCerts.executeQuery();
193 Calendar c = Calendar.getInstance();
194 c.setTimeZone(TimeZone.getTimeZone("UTC"));
197 String csrname = rs.getString("csr_name");
198 int id = rs.getInt("id");
199 System.out.println("sign: " + csrname);
201 String csrType = rs.getString("csr_type");
202 CSRType ct = CSRType.valueOf(csrType);
203 File crt = KeyStorage.locateCrt(id);
205 String keyUsage = rs.getString("keyUsage");
206 String ekeyUsage = rs.getString("extendedKeyUsage");
208 Timestamp from = rs.getTimestamp("executeFrom");
209 String length = rs.getString("executeTo");
213 fromDate = new Date(System.currentTimeMillis());
215 fromDate = new Date(from.getTime());
217 if (length.endsWith("m") || length.endsWith("y")) {
218 String num = length.substring(0, length.length() - 1);
219 int inter = Integer.parseInt(num);
221 if (length.endsWith("m")) {
222 c.add(Calendar.MONTH, inter);
224 c.add(Calendar.YEAR, inter);
226 toDate = c.getTime();
228 toDate = CertificateValiditySelector.getDateFormat().parse(length);
231 getSANSs.setInt(1, id);
232 ResultSet san = getSANSs.executeQuery();
234 File f = new File("keys", "SANFile" + System.currentTimeMillis() + (counter++) + ".cfg");
235 PrintWriter cfg = new PrintWriter(f);
236 boolean first = true;
241 cfg.print("subjectAltName=");
244 cfg.print(san.getString("type"));
246 cfg.print(san.getString("contents"));
249 cfg.println("keyUsage=" + keyUsage);
250 cfg.println("extendedKeyUsage=" + ekeyUsage);
253 int rootcert = rs.getInt("rootcert");
254 String ca = "unassured";
257 } else if (rootcert == 1) {
261 String[] call = new String[] {
264 "../../" + csrname,//
266 "../" + ca + ".crt",//
268 "../" + ca + ".key",//
270 "../../" + crt.getPath(),//
273 sdf.format(fromDate),//
275 sdf.format(toDate),//
278 rs.getString("md"),//
280 "../" + f.getName(),//
283 rs.getString("subject"),//
285 "../selfsign.config"//
288 if (ct == CSRType.SPKAC) {
291 Process p1 = Runtime.getRuntime().exec(call, null, new File("keys/unassured.ca"));
293 int waitFor = p1.waitFor();
296 try (InputStream is = new FileInputStream(crt)) {
297 CertificateFactory cf = CertificateFactory.getInstance("X.509");
298 X509Certificate crtp = (X509Certificate) cf.generateCertificate(is);
299 BigInteger serial = crtp.getSerialNumber();
300 updateMail.setString(1, crt.getPath());
301 updateMail.setString(2, serial.toString(16));
302 updateMail.setInt(3, id);
303 updateMail.execute();
305 finishJob.setInt(1, rs.getInt("jobid"));
307 System.out.println("signed: " + id);
311 BufferedReader br = new BufferedReader(new InputStreamReader(p1.getErrorStream()));
313 while ((s = br.readLine()) != null) {
314 System.out.println(s);
317 } catch (GeneralSecurityException e) {
319 } catch (IOException e) {
321 } catch (SQLException e) {
323 } catch (ParseException e) {
325 } catch (InterruptedException e1) {
326 e1.printStackTrace();
328 System.out.println("Error with: " + id);
329 warnMail.setInt(1, rs.getInt("jobid"));