import ca/root -noprompt
import ca/assured
import ca/unassured
+import ca/orga
+import ca/orgaSign
+import ca/codesign
-for i in ca/{,un}assured_*; do
+for i in ca/*_*_*; do
import ${i%.crt}
done
--- /dev/null
+package org.cacert.gigi.api;
+
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.cacert.gigi.dbObjects.CertificateOwner;
+import org.cacert.gigi.dbObjects.User;
+import org.cacert.gigi.pages.LoginPage;
+
+public abstract class APIPoint {
+
+ public void process(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ X509Certificate cert = LoginPage.getCertificateFromRequest(req);
+ if (cert == null) {
+ resp.sendError(403, "Error, cert authing required.");
+ return;
+ }
+ String serial = LoginPage.extractSerialFormCert(cert);
+ CertificateOwner u = CertificateOwner.getByEnabledSerial(serial);
+ if (u == null) {
+ resp.sendError(403, "Error, cert authing required.");
+ return;
+ }
+
+ if ( !req.getMethod().equals("POST")) {
+ resp.sendError(500, "Error, POST required.");
+ return;
+ }
+ if (req.getQueryString() != null) {
+ resp.sendError(500, "Error, no query String allowed.");
+ return;
+ }
+ process(req, resp, u);
+ }
+
+ protected void process(HttpServletRequest req, HttpServletResponse resp, CertificateOwner u) throws IOException {
+ if (u instanceof User) {
+ process(req, resp, (User) u);
+ } else {
+ resp.sendError(500, "Error, requires a User certificate.");
+ return;
+ }
+ }
+
+ protected void process(HttpServletRequest req, HttpServletResponse resp, User u) throws IOException {
+
+ }
+}
--- /dev/null
+package org.cacert.gigi.api;
+
+import java.io.IOException;
+import java.util.Date;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.cacert.gigi.dbObjects.CATS;
+import org.cacert.gigi.dbObjects.CertificateOwner;
+import org.cacert.gigi.dbObjects.Organisation;
+import org.cacert.gigi.dbObjects.User;
+
+public class CATSImport extends APIPoint {
+
+ public static final String PATH = "/cats_import";
+
+ @Override
+ public void process(HttpServletRequest req, HttpServletResponse resp, CertificateOwner u) throws IOException {
+ if ( !(u instanceof Organisation)) {
+ resp.sendError(500, "Error, invalid cert");
+ return;
+ }
+ if ( !"CAcert".equals(((Organisation) u).getName())) {
+ resp.sendError(500, "Error, invalid cert");
+ return;
+
+ }
+ String target = req.getParameter("serial");
+ String testType = req.getParameter("variant");
+ String date = req.getParameter("date");
+ if (target == null || testType == null || date == null) {
+ resp.sendError(500, "Error, requires serial, variant and date");
+ return;
+ }
+ // TODO is "byEnabledSerial" desired?
+ CertificateOwner o = CertificateOwner.getByEnabledSerial(target);
+ if ( !(o instanceof User)) {
+ resp.sendError(500, "Error, requires valid serial");
+ return;
+ }
+ System.out.println("CATS: " + target + ": " + testType);
+ User targetUser = (User) o;
+ System.out.println(targetUser.getId());
+ CATS.enterResult(targetUser, testType, new Date(Long.parseLong(date)));
+ }
+}
--- /dev/null
+package org.cacert.gigi.api;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.cacert.gigi.GigiApiException;
+import org.cacert.gigi.dbObjects.Certificate;
+import org.cacert.gigi.dbObjects.Certificate.CertificateStatus;
+import org.cacert.gigi.dbObjects.Job;
+import org.cacert.gigi.dbObjects.User;
+import org.cacert.gigi.pages.account.certs.CertificateRequest;
+import org.cacert.gigi.util.AuthorizationContext;
+import org.cacert.gigi.util.PEM;
+
+public class CreateCertificate extends APIPoint {
+
+ public static final String PATH = "/account/certs/new";
+
+ @Override
+ public void process(HttpServletRequest req, HttpServletResponse resp, User u) throws IOException {
+ String csr = req.getParameter("csr");
+ if (csr == null) {
+ resp.sendError(500, "Error, no CSR found");
+ return;
+ }
+ try {
+ CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u), csr);
+ Certificate result = cr.draft();
+ Job job = result.issue(null, "2y", u);
+ job.waitFor(60000);
+ if (result.getStatus() != CertificateStatus.ISSUED) {
+ resp.sendError(510, "Error, issuing timed out");
+ return;
+ }
+ resp.getWriter().println(PEM.encode("CERTIFICATE", result.cert().getEncoded()));
+ return;
+ } catch (GeneralSecurityException e) {
+ e.printStackTrace();
+ } catch (GigiApiException e) {
+ e.printStackTrace();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+}
import java.io.IOException;
import java.io.InputStreamReader;
-import java.security.GeneralSecurityException;
-import java.security.cert.X509Certificate;
+import java.util.HashMap;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.cacert.gigi.GigiApiException;
-import org.cacert.gigi.dbObjects.Certificate;
-import org.cacert.gigi.dbObjects.Certificate.CertificateStatus;
-import org.cacert.gigi.dbObjects.Job;
-import org.cacert.gigi.dbObjects.User;
-import org.cacert.gigi.pages.LoginPage;
-import org.cacert.gigi.pages.account.certs.CertificateRequest;
-import org.cacert.gigi.util.AuthorizationContext;
-import org.cacert.gigi.util.PEM;
-
public class GigiAPI extends HttpServlet {
private static final long serialVersionUID = 659963677032635817L;
+ HashMap<String, APIPoint> api = new HashMap<>();
+
+ public GigiAPI() {
+ api.put(CreateCertificate.PATH, new CreateCertificate());
+ api.put(RevokeCertificate.PATH, new RevokeCertificate());
+ api.put(CATSImport.PATH, new CATSImport());
+ }
+
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String pi = req.getPathInfo();
System.out.println(strB);
return;
}
- X509Certificate cert = LoginPage.getCertificateFromRequest(req);
- if (cert == null) {
- resp.sendError(403, "Error, cert authing required.");
- return;
- }
- String serial = LoginPage.extractSerialFormCert(cert);
- User u = LoginPage.fetchUserBySerial(serial);
- if (u == null) {
- resp.sendError(403, "Error, cert authing required.");
- return;
- }
-
- if (pi.equals("/account/certs/new")) {
- if ( !req.getMethod().equals("POST")) {
- resp.sendError(500, "Error, POST required.");
- return;
- }
- if (req.getQueryString() != null) {
- resp.sendError(500, "Error, no query String allowed.");
- return;
- }
- String csr = req.getParameter("csr");
- if (csr == null) {
- resp.sendError(500, "Error, no CSR found");
- return;
- }
- try {
- CertificateRequest cr = new CertificateRequest(new AuthorizationContext(u, u), csr);
- Certificate result = cr.draft();
- Job job = result.issue(null, "2y", u);
- job.waitFor(60000);
- if (result.getStatus() != CertificateStatus.ISSUED) {
- resp.sendError(510, "Error, issuing timed out");
- return;
- }
- resp.getWriter().println(PEM.encode("CERTIFICATE", result.cert().getEncoded()));
- return;
- } catch (GeneralSecurityException e) {
- e.printStackTrace();
- } catch (GigiApiException e) {
- e.printStackTrace();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- } else if (pi.equals("/account/certs/revoke")) {
-
- if ( !req.getMethod().equals("POST")) {
- resp.sendError(500, "Error, POST required.");
- return;
- }
- if (req.getQueryString() != null) {
- resp.sendError(500, "Error, no query String allowed.");
- return;
- }
- String tserial = req.getParameter("serial");
- if (tserial == null) {
- resp.sendError(500, "Error, no Serial found");
- return;
- }
- try {
- Certificate c = Certificate.getBySerial(tserial);
- if (c == null || c.getOwner() != u) {
- resp.sendError(403, "Access Denied");
- return;
- }
- Job job = c.revoke();
- job.waitFor(60000);
- if (c.getStatus() != CertificateStatus.REVOKED) {
- resp.sendError(510, "Error, issuing timed out");
- return;
- }
- resp.getWriter().println("OK");
- return;
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ APIPoint p = api.get(pi);
+ if (p != null) {
+ p.process(req, resp);
}
}
}
--- /dev/null
+package org.cacert.gigi.api;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.cacert.gigi.dbObjects.Certificate;
+import org.cacert.gigi.dbObjects.Certificate.CertificateStatus;
+import org.cacert.gigi.dbObjects.Job;
+import org.cacert.gigi.dbObjects.User;
+
+public class RevokeCertificate extends APIPoint {
+
+ public static final String PATH = "/account/certs/revoke";
+
+ @Override
+ public void process(HttpServletRequest req, HttpServletResponse resp, User u) throws IOException {
+
+ if ( !req.getMethod().equals("POST")) {
+ resp.sendError(500, "Error, POST required.");
+ return;
+ }
+ if (req.getQueryString() != null) {
+ resp.sendError(500, "Error, no query String allowed.");
+ return;
+ }
+ String tserial = req.getParameter("serial");
+ if (tserial == null) {
+ resp.sendError(500, "Error, no Serial found");
+ return;
+ }
+ try {
+ Certificate c = Certificate.getBySerial(tserial);
+ if (c == null || c.getOwner() != u) {
+ resp.sendError(403, "Access Denied");
+ return;
+ }
+ Job job = c.revoke();
+ job.waitFor(60000);
+ if (c.getStatus() != CertificateStatus.REVOKED) {
+ resp.sendError(510, "Error, issuing timed out");
+ return;
+ }
+ resp.getWriter().println("OK");
+ return;
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+}
if (string.equals("")) {
continue;
}
- if ((string.contains("profiles") || string.contains("cacerts")) && type != ImportType.PRODUCTION) {
+ if ((string.contains("profiles") || string.contains("cacerts") || string.contains("cats_type")) && type != ImportType.PRODUCTION) {
continue;
}
string = DatabaseConnection.preprocessQuery(string);
--- /dev/null
+package org.cacert.gigi.dbObjects;
+
+import java.sql.Timestamp;
+import java.util.Date;
+import java.util.HashMap;
+
+import org.cacert.gigi.database.DatabaseConnection;
+import org.cacert.gigi.database.GigiPreparedStatement;
+import org.cacert.gigi.database.GigiResultSet;
+
+public class CATS {
+
+ private static HashMap<String, Integer> names = new HashMap<>();
+
+ public static final String ASSURER_CHALLANGE_NAME = "Assurer's Challange";
+
+ public static final int ASSURER_CHALLANGE_ID;
+
+ private CATS() {
+
+ }
+
+ static {
+ GigiResultSet res = DatabaseConnection.getInstance().prepare("SELECT `id`, `type_text` FROM `cats_type`").executeQuery();
+ while (res.next()) {
+ names.put(res.getString(2), res.getInt(1));
+ }
+ ASSURER_CHALLANGE_ID = getID(ASSURER_CHALLANGE_NAME);
+ }
+
+ public static synchronized int getID(String name) {
+ Integer i = names.get(name);
+ if (i == null) {
+ GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("INSERT INTO `cats_type` SET `type_text`=?");
+ ps.setString(1, name);
+ ps.execute();
+ i = ps.lastInsertId();
+ names.put(name, i);
+ }
+ return i;
+ }
+
+ public static void enterResult(User user, String testType, Date passDate) {
+ GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("INSERT INTO `cats_passed` SET `user_id`=?, `variant_id`=?, `pass_date`=?");
+ ps.setInt(1, user.getId());
+ ps.setInt(2, getID(testType));
+ ps.setTimestamp(3, new Timestamp(passDate.getTime()));
+ ps.execute();
+ }
+}
return entries.toArray(new String[0]);
}
+ public static CertificateOwner getByEnabledSerial(String serial) {
+ GigiPreparedStatement prep = DatabaseConnection.getInstance().prepare("SELECT `memid` FROM `certs` WHERE serial=? AND `disablelogin`='0' AND `revoked` is NULL");
+ prep.setString(1, serial.toLowerCase());
+ GigiResultSet res = prep.executeQuery();
+ if (res.next()) {
+ return getById(res.getInt(1));
+ }
+ return null;
+ }
}
}
public boolean hasPassedCATS() {
- GigiPreparedStatement query = DatabaseConnection.getInstance().prepare("SELECT 1 FROM `cats_passed` where `user_id`=? AND `variant_id`=1");
+ GigiPreparedStatement query = DatabaseConnection.getInstance().prepare("SELECT 1 FROM `cats_passed` where `user_id`=? AND `variant_id`=?");
query.setInt(1, getId());
+ query.setInt(2, CATS.ASSURER_CHALLANGE_ID);
try (GigiResultSet rs = query.executeQuery()) {
if (rs.next()) {
return true;
import org.cacert.gigi.database.DatabaseConnection;
import org.cacert.gigi.database.GigiPreparedStatement;
import org.cacert.gigi.database.GigiResultSet;
+import org.cacert.gigi.dbObjects.CertificateOwner;
import org.cacert.gigi.dbObjects.Group;
import org.cacert.gigi.dbObjects.User;
import org.cacert.gigi.localisation.Language;
if ( !serial.matches("[A-Fa-f0-9]+")) {
throw new Error("serial malformed.");
}
- GigiPreparedStatement ps = DatabaseConnection.getInstance().prepare("SELECT `memid` FROM `certs` WHERE `serial`=? AND `disablelogin`='0' AND `revoked` is NULL");
- ps.setString(1, serial.toLowerCase());
- GigiResultSet rs = ps.executeQuery();
- User user = null;
- if (rs.next()) {
- user = User.getById(rs.getInt(1));
- } else {
- System.out.println("User with serial " + serial + " not found.");
+
+ CertificateOwner o = CertificateOwner.getByEnabledSerial(serial);
+ if (o == null || !(o instanceof User)) {
+ return null;
}
- rs.close();
- return user;
+ return (User) o;
}
public static X509Certificate getCertificateFromRequest(HttpServletRequest req) {
--- /dev/null
+package org.cacert.gigi.api;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+import org.cacert.gigi.GigiApiException;
+import org.cacert.gigi.dbObjects.CATS;
+import org.cacert.gigi.dbObjects.Certificate;
+import org.cacert.gigi.dbObjects.Certificate.CSRType;
+import org.cacert.gigi.dbObjects.Certificate.SANType;
+import org.cacert.gigi.dbObjects.CertificateProfile;
+import org.cacert.gigi.dbObjects.Digest;
+import org.cacert.gigi.dbObjects.Group;
+import org.cacert.gigi.dbObjects.Organisation;
+import org.cacert.gigi.dbObjects.User;
+import org.cacert.gigi.testUtils.ClientTest;
+import org.junit.Test;
+
+public class ImportCATSResult extends ClientTest {
+
+ @Test
+ public void testImportCATS() throws GigiApiException, IOException, GeneralSecurityException, InterruptedException {
+ makeAssurer(id);
+ Certificate target = new Certificate(u, u, Certificate.buildDN("EMAIL", email), Digest.SHA256, generatePEMCSR(generateKeypair(), "EMAIL=" + email), CSRType.CSR, CertificateProfile.getByName("client"), new Certificate.SubjectAlternateName(SANType.EMAIL, "cats@cacert.org"));
+ target.issue(null, "2y", u).waitFor(60000);
+
+ grant(u.getEmail(), Group.ORGASSURER);
+ clearCaches();
+ u = User.getById(u.getId());
+ Organisation o = new Organisation("CAcert", "NA", "NA", "NA", "contact@cacert.org", u);
+ KeyPair kp = generateKeypair();
+ String key1 = generatePEMCSR(kp, "EMAIL=cats@cacert.org");
+ Certificate c = new Certificate(o, u, Certificate.buildDN("EMAIL", "cats@cacert.org"), Digest.SHA256, key1, CSRType.CSR, CertificateProfile.getByName("client-orga"), new Certificate.SubjectAlternateName(SANType.EMAIL, "cats@cacert.org"));
+ final PrivateKey pk = kp.getPrivate();
+ c.issue(null, "2y", u).waitFor(60000);
+ final X509Certificate ce = c.cert();
+
+ assertEquals(1, u.getTrainings().length);
+ apiRequest(target.cert().getSerialNumber().toString(16), "Test Training", pk, ce);
+ assertEquals(2, u.getTrainings().length);
+
+ User u2 = User.getById(createVerifiedUser("fn", "ln", createUniqueName() + "@example.com", TEST_PASSWORD));
+ Certificate target2 = new Certificate(u2, u2, Certificate.buildDN("EMAIL", u2.getEmail()), Digest.SHA256, generatePEMCSR(generateKeypair(), "EMAIL=" + u2.getEmail()), CSRType.CSR, CertificateProfile.getByName("client"), new Certificate.SubjectAlternateName(SANType.EMAIL, "cats@cacert.org"));
+ target2.issue(null, "2y", u).waitFor(60000);
+ assertEquals(0, u2.getTrainings().length);
+ assertFalse(u2.hasPassedCATS());
+ apiRequest(target2.cert().getSerialNumber().toString(16), "Test Training", pk, ce);
+ assertEquals(1, u2.getTrainings().length);
+ assertFalse(u2.hasPassedCATS());
+ apiRequest(target2.cert().getSerialNumber().toString(16), CATS.ASSURER_CHALLANGE_NAME, pk, ce);
+ assertEquals(2, u2.getTrainings().length);
+ assertTrue(u2.hasPassedCATS());
+
+ }
+
+ private void apiRequest(String target, String test, final PrivateKey pk, final X509Certificate ce) throws IOException, MalformedURLException, NoSuchAlgorithmException, KeyManagementException, UnsupportedEncodingException, GeneralSecurityException {
+ HttpURLConnection connection = (HttpURLConnection) new URL("https://" + getServerName().replaceFirst("^www.", "api.") + CATSImport.PATH).openConnection();
+ authenticateClientCert(pk, ce, connection);
+ connection.setDoOutput(true);
+ OutputStream os = connection.getOutputStream();
+ os.write(("serial=" + target + "&variant=" + URLEncoder.encode(test, "UTF-8") + "&date=" + System.currentTimeMillis()).getBytes("UTF-8"));
+ System.out.println(connection.getResponseCode());
+ System.out.println(connection.getResponseMessage());
+ }
+}
final PrivateKey pk = kp.getPrivate();
c.issue(null, "2y", u).waitFor(60000);
final X509Certificate ce = c.cert();
- HttpURLConnection connection = (HttpURLConnection) new URL("https://" + getServerName().replaceFirst("^www.", "api.") + "/account/certs/new").openConnection();
+ HttpURLConnection connection = (HttpURLConnection) new URL("https://" + getServerName().replaceFirst("^www.", "api.") + CreateCertificate.PATH).openConnection();
authenticateClientCert(pk, ce, connection);
connection.setDoOutput(true);
OutputStream os = connection.getOutputStream();