import java.security.GeneralSecurityException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
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;
public class Certificate {
+ public enum SANType {
+ EMAIL("email"), DNS("DNS");
+
+ private final String opensslName;
+
+ private SANType(String opensslName) {
+ this.opensslName = opensslName;
+ }
+
+ public String getOpensslName() {
+ return opensslName;
+ }
+ }
+
+ public static class SubjectAlternateName implements Comparable<SubjectAlternateName> {
+
+ private SANType type;
+
+ private String name;
+
+ public SubjectAlternateName(SANType type, String name) {
+ this.type = type;
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public SANType getType() {
+ return type;
+ }
+
+ @Override
+ public int compareTo(SubjectAlternateName o) {
+ int i = type.compareTo(o.type);
+ if (i != 0) {
+ return i;
+ }
+ return name.compareTo(o.name);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ SubjectAlternateName other = (SubjectAlternateName) obj;
+ if (name == null) {
+ if (other.name != null) {
+ return false;
+ }
+ } else if ( !name.equals(other.name)) {
+ return false;
+ }
+ if (type != other.type) {
+ return false;
+ }
+ return true;
+ }
+
+ }
+
public enum CSRType {
CSR, SPKAC;
}
private CSRType csrType;
- public Certificate(int ownerId, String dn, String md, String csr, CSRType csrType) {
+ private List<SubjectAlternateName> sans;
+
+ private CertificateProfile profile;
+
+ public Certificate(int ownerId, String dn, String md, String csr, CSRType csrType, CertificateProfile profile, SubjectAlternateName... sans) {
this.ownerId = ownerId;
this.dn = dn;
this.md = md;
this.csr = csr;
this.csrType = csrType;
+ this.profile = profile;
+ this.sans = Arrays.asList(sans);
}
private Certificate(String serial) {
try {
- PreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT id,subject, md, csr_name, crt_name,memid FROM `emailcerts` WHERE serial=?");
+ PreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT id,subject, md, csr_name, crt_name,memid, profile FROM `certs` WHERE serial=?");
ps.setString(1, serial);
ResultSet rs = ps.executeQuery();
if ( !rs.next()) {
csrName = rs.getString(4);
crtName = rs.getString(5);
ownerId = rs.getInt(6);
+ profile = CertificateProfile.getById(rs.getInt(7));
this.serial = serial;
+
+ PreparedStatement ps2 = DatabaseConnection.getInstance().prepare("SELECT contents, type FROM `subjectAlternativeNames` WHERE certId=?");
+ ps2.setInt(1, id);
+ ResultSet rs2 = ps2.executeQuery();
+ sans = new LinkedList<>();
+ while (rs2.next()) {
+ sans.add(new SubjectAlternateName(SANType.valueOf(rs2.getString("type").toUpperCase()), rs2.getString("contents")));
+ }
+ rs2.close();
+
rs.close();
} catch (SQLException e) {
e.printStackTrace();
if (id == 0) {
return CertificateStatus.DRAFT;
}
- PreparedStatement searcher = DatabaseConnection.getInstance().prepare("SELECT crt_name, created, revoked, serial FROM emailcerts WHERE id=?");
+ PreparedStatement searcher = DatabaseConnection.getInstance().prepare("SELECT crt_name, created, revoked, serial FROM certs WHERE id=?");
searcher.setInt(1, id);
ResultSet rs = searcher.executeQuery();
if ( !rs.next()) {
return CertificateStatus.REVOKED;
}
- public Job issue() throws IOException, SQLException {
+ /**
+ * @param start
+ * the date from which on the certificate should be valid. (or
+ * null if it should be valid instantly)
+ * @param period
+ * the period for which the date should be valid. (a
+ * <code>yyyy-mm-dd</code> or a "2y" (2 calendar years), "6m" (6
+ * months)
+ * @return A job which can be used to monitor the progress of this task.
+ * @throws IOException
+ * for problems with writing the CSR/SPKAC
+ * @throws SQLException
+ * for problems with writing to the DB
+ * @throws GigiApiException
+ * if the period is bogus
+ */
+ public Job issue(Date start, String period) throws IOException, SQLException, GigiApiException {
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=?, csr_type=?, crt_name='', memid=?, profile=1");
+ PreparedStatement inserter = DatabaseConnection.getInstance().prepare("INSERT INTO certs SET md=?, subject=?, csr_type=?, crt_name='', memid=?, profile=?");
inserter.setString(1, md);
inserter.setString(2, dn);
inserter.setString(3, csrType.toString());
inserter.setInt(4, ownerId);
+ inserter.setInt(5, profile.getId());
inserter.execute();
id = DatabaseConnection.lastInsertId(inserter);
File csrFile = KeyStorage.locateCsr(id);
// TODO draft to insert SANs
PreparedStatement san = DatabaseConnection.getInstance().prepare("INSERT INTO subjectAlternativeNames SET certId=?, contents=?, type=?");
- san.setInt(1, id);
- san.setString(2, "<address>");
- san.setString(3, "email");
- // san.execute();
+ for (SubjectAlternateName subjectAlternateName : sans) {
+ san.setInt(1, id);
+ san.setString(2, subjectAlternateName.getName());
+ san.setString(3, subjectAlternateName.getType().getOpensslName());
+ san.execute();
+ }
- PreparedStatement updater = DatabaseConnection.getInstance().prepare("UPDATE emailcerts SET csr_name=? WHERE id=?");
+ PreparedStatement updater = DatabaseConnection.getInstance().prepare("UPDATE certs SET csr_name=? WHERE id=?");
updater.setString(1, csrName);
updater.setInt(2, id);
updater.execute();
- return Job.submit(this, JobType.SIGN);
+ return Job.sign(this, start, period);
}
if (getStatus() != CertificateStatus.ISSUED) {
throw new IllegalStateException();
}
- return Job.submit(this, JobType.REVOKE);
+ return Job.revoke(this);
}
return ownerId;
}
+ public List<SubjectAlternateName> getSANs() {
+ return Collections.unmodifiableList(sans);
+ }
+
+ public CertificateProfile getProfile() {
+ return profile;
+ }
+
public static Certificate getBySerial(String serial) {
// TODO caching?
try {