diff options
author | Yuuta Liang <yuutaw@students.cs.ubc.ca> | 2023-10-14 05:12:06 +0800 |
---|---|---|
committer | Yuuta Liang <yuutaw@students.cs.ubc.ca> | 2023-10-14 05:12:06 +0800 |
commit | 0bcc057e741af3fbc108f42b75f9d42f48f6a51e (patch) | |
tree | d638c81c0778554a8902efc59000e61db74060be /src/main/ui/MainScreen.java | |
parent | f369da34cf9aca151df0150d90e651e6a88ee700 (diff) | |
download | jca-0bcc057e741af3fbc108f42b75f9d42f48f6a51e.tar jca-0bcc057e741af3fbc108f42b75f9d42f48f6a51e.tar.gz jca-0bcc057e741af3fbc108f42b75f9d42f48f6a51e.tar.bz2 jca-0bcc057e741af3fbc108f42b75f9d42f48f6a51e.zip |
Implement the CA
Signed-off-by: Yuuta Liang <yuutaw@students.cs.ubc.ca>
Diffstat (limited to 'src/main/ui/MainScreen.java')
-rw-r--r-- | src/main/ui/MainScreen.java | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/src/main/ui/MainScreen.java b/src/main/ui/MainScreen.java new file mode 100644 index 0000000..69cb32c --- /dev/null +++ b/src/main/ui/MainScreen.java @@ -0,0 +1,200 @@ +package ui; + +import model.asn1.ASN1Object; +import model.asn1.UtcTime; +import model.asn1.exceptions.ParseException; +import model.asn1.parsing.BytesReader; +import model.ca.Template; +import model.csr.CertificationRequest; +import model.pki.cert.Certificate; +import model.pki.crl.Reason; +import model.pki.crl.RevokedCertificate; + +import java.io.*; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Optional; + +public class MainScreen implements UIHandler { + private final JCA session; + + /** + * EFFECTS: Init with the parent session. + */ + public MainScreen(JCA session) { + this.session = session; + } + + @Override + public void help() { + System.out.print("mgmt\tView and manage the CA certificate\n" + + "issue\tIssue a certificate\n" + + "show\tList all issued certificates\n" + + "export\tExport a certificate to file (DER)\n" + + "template\tManage templates\n" + + "revoke\tRevoke a certificate\n" + + "crl\t\tSign CRL\n" + + "log\t\tView audit logs\n" + + "exit\tExit\n" + + "help\tPrint this message\n"); + } + + @Override + public void show() { + session.getCa().getSigned().forEach(cert -> { + System.out.printf("%s\t%d\t%s\n", + cert.getCertificate().getSubject().toString(), + cert.getCertificate().getSerialNumber().getLong(), + session.getCa().getRevoked().stream().anyMatch(rev -> rev.getSerialNumber().getLong() + == cert.getCertificate().getSerialNumber().getLong()) ? "REVOKED" : "OK"); + }); + } + + private CertificationRequest handleIssueInputCSR() { + try { + return new CertificationRequest(new BytesReader(session.handleInputPEM("CERTIFICATE REQUEST")), + false); + } catch (ParseException e) { + System.out.println(e.getMessage()); + return null; + } + } + + private void handleIssue(String... args) { + if (!session.checkCA(true)) { + return; + } + if (args.length <= 1) { + System.out.println("Usage: issue <template>"); + return; + } + Template tmp = session.findTemplate(args[1], true); + if (tmp == null) { + System.out.println("Cannot find the template specified"); + return; + } + CertificationRequest req = handleIssueInputCSR(); + if (req != null) { + session.setScreen(Screen.ISSUE, req, new Template(tmp.getName(), + true, + tmp.getSubject(), + tmp.getValidity())); + } + } + + /** + * EFFECTS: Find issued and not revoked certificate by serial. Return null if not found. + */ + private Certificate findCertBySerial(int serial) { + Optional<Certificate> c = session.getCa().getSigned() + .stream() + .filter(cert -> cert.getCertificate().getSerialNumber().getLong() == serial) + .findFirst(); + if (c.isEmpty()) { + System.out.println("Cannot find the certificate specified"); + return null; + } + if (session.getCa().getRevoked().stream().anyMatch(rev -> rev.getSerialNumber().getLong() == serial)) { + System.out.println("The certificate has already been revoked."); + return null; + } + return c.get(); + } + + private void handleRevoke(String... args) { + if (args.length < 3) { + System.out.println("Usage: revoke <serial> <reason>"); + return; + } + try { + final Reason reason = Reason.valueOf(args[2]); + int serial = Integer.parseInt(args[1]); + Certificate c = findCertBySerial(serial); + if (c == null) { + return; + } + session.getCa().revoke(new RevokedCertificate(ASN1Object.TAG_SEQUENCE, null, + c.getCertificate().getSerialNumber(), + new UtcTime(UtcTime.TAG, null, ZonedDateTime.now(ZoneId.of("UTC"))), reason)); + session.log("A certificate has been revoked."); + } catch (IllegalArgumentException ignored) { + System.out.println("Illegal serial number or reason"); + } + } + + private void handleExport(String... args) { + if (args.length < 3) { + System.out.println("Usage: export <serial> <path>"); + return; + } + try { + int serial = Integer.parseInt(args[1]); + Certificate c = findCertBySerial(serial); + if (c == null) { + return; + } + final File fd = new File(args[2]); + final OutputStream out = new FileOutputStream(fd); + out.write(Utils.byteToByte(c.encodeDER())); + out.close(); + } catch (IllegalArgumentException ignored) { + System.out.println("Illegal serial number or reason"); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + } + + private void handleCRL() { + if (!session.checkCA(true)) { + return; + } + try { + System.out.println(Utils.toPEM(session.getCa().signCRL().encodeDER(), "X509 CRL")); + session.log("A CRL was signed"); + } catch (Throwable e) { + System.out.println(e.getMessage()); + } + } + + private void handleLog() { + session.getLogs().forEach(System.out::println); + } + + @Override + public void command(String... args) { + switch (args[0]) { + case "mgmt": + session.setScreen(Screen.MGMT); + return; + case "issue": + handleIssue(args); + return; + case "revoke": + handleRevoke(args); + return; + case "export": + handleExport(args); + return; + case "template": + session.setScreen(Screen.TEMPLATES); + return; + case "crl": + handleCRL(); + return; + case "log": + handleLog(); + return; + } + help(); + } + + @Override + public Screen exit() { + return null; + } + + @Override + public String getPS1() { + return "/ %"; + } +} |