`subject` text NOT NULL,
`keytype` char(2) NOT NULL DEFAULT 'NS',
`codesign` tinyint(1) NOT NULL DEFAULT '0',
+ `md` enum('md5','sha1','sha256','sha512') NOT NULL DEFAULT 'sha512',
+ `rootcert` int(2) NOT NULL DEFAULT '1',
+ `type` enum('client', 'server') DEFAULT NULL,
+
`csr_name` varchar(255) NOT NULL DEFAULT '',
`crt_name` varchar(255) NOT NULL DEFAULT '',
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`revoked` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`expire` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
- `warning` tinyint(1) NOT NULL DEFAULT '0',
`renewed` tinyint(1) NOT NULL DEFAULT '0',
- `rootcert` int(2) NOT NULL DEFAULT '1',
- `md` enum('md5','sha1','sha256','sha512') NOT NULL DEFAULT 'sha512',
- `type` tinyint(4) DEFAULT NULL,
`disablelogin` int(1) NOT NULL DEFAULT '0',
`pkhash` char(40) DEFAULT NULL,
`certhash` char(40) DEFAULT NULL,
- `coll_found` tinyint(1) NOT NULL,
`description` varchar(100) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `emailcerts_pkhash` (`pkhash`),
KEY `emailcrt` (`crt_name`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
+DROP TABLE IF EXISTS `clientcerts`;
+CREATE TABLE `clientcerts` (
+ `id` int(11) NOT NULL,
+ `disablelogin` int(1) NOT NULL DEFAULT '0',
+
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
+
+
+
+DROP TABLE IF EXISTS `jobs`;
+CREATE TABLE `jobs` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `targetId` int(11) NOT NULL,
+ `task` enum('sign','revoke') NOT NULL,
+ `state` enum('open', 'done', 'error') NOT NULL DEFAULT 'open',
+ `warning` int(2) NOT NULL DEFAULT '0',
+ PRIMARY KEY (`id`),
+ KEY `state` (`state`)
+) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;
+
+
DROP TABLE IF EXISTS `notary`;
CREATE TABLE `notary` (
`id` int(11) NOT NULL AUTO_INCREMENT,
import java.sql.SQLException;
import org.cacert.gigi.database.DatabaseConnection;
+import org.cacert.gigi.util.Job;
+import org.cacert.gigi.util.Job.JobType;
import org.cacert.gigi.util.KeyStorage;
import org.cacert.gigi.util.Notary;
* This certificate is not in the database, has no id and only exists as
* this java object.
*/
- DRAFT(false),
- /**
- * The certificate has been written to the database and is waiting for
- * the signer to sign it.
- */
- SIGNING(true),
+ DRAFT(),
/**
* The certificate has been signed. It is stored in the database.
* {@link Certificate#cert()} is valid.
*/
- ISSUED(false),
- /**
- * The cetrificate is about to be revoked by the signer bot.
- */
- BEING_REVOKED(true),
+ ISSUED(),
/**
* The certificate has been revoked.
*/
- REVOKED(false),
+ REVOKED(),
/**
* If this certificate cannot be updated because an error happened in
* the signer.
*/
- ERROR(false);
+ ERROR();
- private boolean unstable;
-
- private CertificateStatus(boolean unstable) {
- this.unstable = unstable;
- }
-
- /**
- * Checks, iff this certificate stage will be left by signer actions.
- *
- * @return True, iff this certificate stage will be left by signer
- * actions.
- */
- public boolean isUnstable() {
- return unstable;
+ private CertificateStatus() {
}
}
return CertificateStatus.DRAFT;
}
PreparedStatement searcher = DatabaseConnection.getInstance().prepare(
- "SELECT crt_name, created, revoked, warning, serial FROM emailcerts WHERE id=?");
+ "SELECT crt_name, created, revoked, serial FROM emailcerts WHERE id=?");
searcher.setInt(1, id);
ResultSet rs = searcher.executeQuery();
if (!rs.next()) {
throw new IllegalStateException("Certificate not in Database");
}
- if (rs.getInt(4) >= 3) {
- return CertificateStatus.ERROR;
- }
- if (rs.getString(2) == null) {
- return CertificateStatus.SIGNING;
- }
crtName = rs.getString(1);
- serial = rs.getString(5);
+ serial = rs.getString(4);
+ if (rs.getTime(2) == null) {
+ return CertificateStatus.DRAFT;
+ }
if (rs.getTime(2) != null && rs.getTime(3) == null) {
return CertificateStatus.ISSUED;
}
- if (rs.getTime(2) != null && rs.getString(3).equals("1970-01-01 00:00:00.0")) {
- return CertificateStatus.BEING_REVOKED;
- }
return CertificateStatus.REVOKED;
}
- public void issue() throws IOException {
- try {
- if (getStatus() != CertificateStatus.DRAFT) {
- throw new IllegalStateException();
- }
- Notary.writeUserAgreement(ownerId, "CCA", "issue certificate", "", true, 0);
-
- PreparedStatement inserter = DatabaseConnection.getInstance().prepare(
- "INSERT INTO emailcerts SET md=?, subject=?, coll_found=0, crt_name='', memid=?");
- inserter.setString(1, md);
- inserter.setString(2, dn);
- inserter.setInt(3, ownerId);
- inserter.execute();
- id = DatabaseConnection.lastInsertId(inserter);
- File csrFile = KeyStorage.locateCsr(id);
- csrName = csrFile.getPath();
- FileOutputStream fos = new FileOutputStream(csrFile);
- fos.write(csr.getBytes());
- fos.close();
-
- PreparedStatement updater = DatabaseConnection.getInstance().prepare(
- "UPDATE emailcerts SET csr_name=? WHERE id=?");
- updater.setString(1, csrName);
- updater.setInt(2, id);
- updater.execute();
- } catch (SQLException e) {
- e.printStackTrace();
+ public Job issue() throws IOException, SQLException {
+ if (getStatus() != CertificateStatus.DRAFT) {
+ throw new IllegalStateException();
}
+ Notary.writeUserAgreement(ownerId, "CCA", "issue certificate", "", true, 0);
+
+ PreparedStatement inserter = DatabaseConnection.getInstance().prepare(
+ "INSERT INTO emailcerts SET md=?, subject=?, crt_name='', memid=?");
+ inserter.setString(1, md);
+ inserter.setString(2, dn);
+ inserter.setInt(3, ownerId);
+ inserter.execute();
+ id = DatabaseConnection.lastInsertId(inserter);
+ File csrFile = KeyStorage.locateCsr(id);
+ csrName = csrFile.getPath();
+ FileOutputStream fos = new FileOutputStream(csrFile);
+ fos.write(csr.getBytes());
+ fos.close();
+
+ PreparedStatement updater = DatabaseConnection.getInstance().prepare(
+ "UPDATE emailcerts SET csr_name=? WHERE id=?");
+ updater.setString(1, csrName);
+ updater.setInt(2, id);
+ updater.execute();
+ return Job.submit(this, JobType.SIGN);
}
- public boolean waitFor(int max) throws SQLException, InterruptedException {
- long start = System.currentTimeMillis();
- while (getStatus().isUnstable()) {
- if (max != 0 && System.currentTimeMillis() - start > max) {
- return false;
- }
- Thread.sleep((long) (2000 + Math.random() * 2000));
- }
- return true;
- }
-
- public void revoke() {
- try {
- if (getStatus() != CertificateStatus.ISSUED) {
- throw new IllegalStateException();
- }
- PreparedStatement inserter = DatabaseConnection.getInstance().prepare(
- "UPDATE emailcerts SET revoked = '1970-01-01' WHERE id=?");
- inserter.setInt(1, id);
- inserter.execute();
- } catch (SQLException e) {
- e.printStackTrace();
+ public Job revoke() throws SQLException {
+ if (getStatus() != CertificateStatus.ISSUED) {
+ throw new IllegalStateException();
}
+ return Job.submit(this, JobType.REVOKE);
}
System.out.println("issuing " + selectedDigest);
result = new Certificate(LoginPage.getUser(req).getId(), "/commonName=CAcert WoT User",
selectedDigest.toString(), this.csr);
- result.issue();
try {
- result.waitFor(60000);
+ result.issue().waitFor(60000);
return true;
} catch (SQLException e) {
e.printStackTrace();
--- /dev/null
+package org.cacert.gigi.util;
+
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+import org.cacert.gigi.Certificate;
+import org.cacert.gigi.database.DatabaseConnection;
+
+public class Job {
+ int id;
+
+ private Job(int id) {
+ this.id = id;
+ }
+
+ public static enum JobType {
+ SIGN("sign"), REVOKE("revoke");
+ private final String name;
+
+ private JobType(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+ }
+
+ public static Job submit(Certificate targetId, JobType type) throws SQLException {
+ PreparedStatement ps = DatabaseConnection.getInstance().prepare("INSERT INTO `jobs` SET targetId=?, task=?");
+ ps.setInt(1, targetId.getId());
+ ps.setString(2, type.getName());
+ ps.execute();
+ return new Job(DatabaseConnection.lastInsertId(ps));
+ }
+
+ public boolean waitFor(int max) throws SQLException, InterruptedException {
+ long start = System.currentTimeMillis();
+ PreparedStatement ps = DatabaseConnection.getInstance().prepare(
+ "SELECT 1 FROM `jobs` WHERE id=? AND state='open'");
+ ps.setInt(1, id);
+ ResultSet rs = ps.executeQuery();
+ while (rs.next()) {
+ rs.close();
+ if (max != 0 && System.currentTimeMillis() - start > max) {
+ return false;
+ }
+ Thread.sleep((long) (2000 + Math.random() * 2000));
+ rs = ps.executeQuery();
+ }
+ rs.close();
+ return true;
+ }
+}
String[] key1 = generateCSR("/CN=testmail@example.com");
Certificate c = new Certificate(1, "/CN=testmail@example.com", "sha256", key1[1]);
final PrivateKey pk = PemKey.parsePEMPrivateKey(key1[0]);
- c.issue();
- c.waitFor(60000);
+ c.issue().waitFor(60000);
final X509Certificate ce = c.cert();
+ System.out.println(ce);
testLogin(pk, ce, true);
}
final PrivateKey pk = PemKey.parsePEMPrivateKey(key1[0]);
testFails(CertificateStatus.DRAFT, c);
- c.issue();
-
- testFails(CertificateStatus.SIGNING, c);
- c.waitFor(60000);
+ c.issue().waitFor(60000);
testFails(CertificateStatus.ISSUED, c);
X509Certificate cert = c.cert();
testLogin(pk, cert, true);
- c.revoke();
-
- testFails(CertificateStatus.BEING_REVOKED, c);
- c.waitFor(60000);
+ c.revoke().waitFor(60000);
testFails(CertificateStatus.REVOKED, c);
testLogin(pk, cert, false);
private void testFails(CertificateStatus status, Certificate c) throws IOException, GeneralSecurityException,
SQLException {
+ assertEquals(status, c.getStatus());
if (status != CertificateStatus.ISSUED) {
try {
c.revoke();
- fail("is in invalid state");
+ fail(status + " is in invalid state");
} catch (IllegalStateException ise) {
}
if (status != CertificateStatus.DRAFT) {
try {
c.issue();
- fail("is in invalid state");
+ fail(status + " is in invalid state");
} catch (IllegalStateException ise) {
}
if (status != CertificateStatus.ISSUED) {
try {
c.cert();
- fail("is in invalid state");
+ fail(status + " is in invalid state");
} catch (IllegalStateException ise) {
}
private static PreparedStatement readyMail;
private static PreparedStatement revoke;
private static PreparedStatement revokeCompleted;
+ private static PreparedStatement finishJob;
private static boolean running = true;
private static Thread runner;
throw new IllegalStateException("already running");
}
running = true;
- readyMail = DatabaseConnection.getInstance().prepare(
- "SELECT id, csr_name, subject FROM emailcerts" + " WHERE csr_name is not null AND csr_name != ''"//
- + " AND created=0"//
- + " AND crt_name=''"//
- + " AND warning<3");
+ readyMail = DatabaseConnection
+ .getInstance()
+ .prepare(
+ "SELECT emailcerts.id,emailcerts.csr_name,emailcerts.subject, jobs.id FROM jobs INNER JOIN emailcerts ON emailcerts.id=jobs.targetId"
+ + " WHERE jobs.state='open'"//
+ + " AND task='sign'");
updateMail = DatabaseConnection.getInstance().prepare(
"UPDATE emailcerts SET crt_name=?," + " created=NOW(), serial=? WHERE id=?");
- warnMail = DatabaseConnection.getInstance().prepare("UPDATE emailcerts SET warning=warning+1 WHERE id=?");
+ warnMail = DatabaseConnection.getInstance().prepare(
+ "UPDATE jobs SET warning=warning+1, state=IF(warning<3, 'open','error') WHERE id=?");
revoke = DatabaseConnection.getInstance().prepare(
- "SELECT id, csr_name FROM emailcerts" + " WHERE csr_name is not null"//
- + " AND created != 0"//
- + " AND revoked = '1970-01-01'");
+ "SELECT emailcerts.id, emailcerts.csr_name,jobs.id FROM jobs INNER JOIN emailcerts ON jobs.targetId=emailcerts.id"
+ + " WHERE jobs.state='open' AND task='revoke'");
revokeCompleted = DatabaseConnection.getInstance().prepare("UPDATE emailcerts SET revoked=NOW() WHERE id=?");
+
+ finishJob = DatabaseConnection.getInstance().prepare("UPDATE jobs SET state='done' WHERE id=?");
+
runner = new Thread() {
@Override
public void run() {
worked = true;
revokeCompleted.setInt(1, id);
revokeCompleted.execute();
+ finishJob.setInt(1, rs.getInt(3));
+ finishJob.execute();
} else {
System.out.println("Failed");
}
updateMail.setString(2, serial.toString(16));
updateMail.setInt(3, id);
updateMail.execute();
- System.out.println("sign: " + id);
+
+ finishJob.setInt(1, rs.getInt(4));
+ finishJob.execute();
+ System.out.println("signed: " + id);
continue;
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
System.out.println("ERROR Afterwards: " + id);
- warnMail.setInt(1, id);
+ warnMail.setInt(1, rs.getInt(4));
warnMail.execute();
} else {
BufferedReader br = new BufferedReader(new InputStreamReader(p1.getErrorStream()));
}
System.out.println(Arrays.toString(call));
System.out.println("ERROR: " + id);
- warnMail.setInt(1, id);
+ warnMail.setInt(1, rs.getInt(4));
warnMail.execute();
}