aboutsummaryrefslogtreecommitdiff
path: root/src/main/ui/MainUI.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/ui/MainUI.java')
-rw-r--r--src/main/ui/MainUI.java690
1 files changed, 674 insertions, 16 deletions
diff --git a/src/main/ui/MainUI.java b/src/main/ui/MainUI.java
index ee35a53..4735c55 100644
--- a/src/main/ui/MainUI.java
+++ b/src/main/ui/MainUI.java
@@ -1,22 +1,680 @@
package ui;
+import model.GroupObserver;
+import model.ObservedData;
+import model.Observer;
+import model.asn1.exceptions.InvalidCAException;
+import model.asn1.exceptions.InvalidDBException;
+import model.asn1.exceptions.ParseException;
+import model.asn1.parsing.BytesReader;
+import model.ca.AuditLogEntry;
+import model.ca.CertificationAuthority;
+import model.ca.Template;
+import model.csr.CertificationRequest;
+import model.pki.cert.Certificate;
+import model.pki.crl.CertificateList;
+import model.pki.crl.RevokedCertificate;
+import persistence.Decoder;
+import persistence.FS;
+import ui.widgets.*;
+
import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
+import java.security.interfaces.RSAPublicKey;
+
+import static java.awt.GridBagConstraints.*;
+import static ui.widgets.UIUtils.*;
+
+/**
+ * The main GUI.
+ * ┌──────────────────────────────┐┌──────────────────────────────┐┌──────────────────────────────┐
+ * │ JCA X ││ JCA X ││ JCA X │
+ * ├──────────────────────────────┤├──────────────────────────────┤├──────────────────────────────┤
+ * │Load Save CSR││Load Save Sign Revoke Export││Load Save New Ena Dis Del│
+ * ├────┬───────┬───────────┬─────┤├────┬───────┬──────────┬──────┤├────┬───────┬─────────────────┤
+ * │ CA │ Certs │ Templates │ ││ CA │ Certs │ Templates│ ││ CA │ Certs │ Templates │
+ * ├────┴───────┴───────────┴─────┤├─┬──┴─────┬─┴────┬─────┼──────┤├─┬──┴───┬───┴─────┬───────────┤
+ * │ Welcome to JCA ││ │ Serial │ Subj │ Bef │ To ││ │ Name │ Subj │ Validity │
+ * │ │├─┴────────┴──────┴─────┴──────┤├─┴──────┴─────────┴───────────┤
+ * │ CA certificate: Install CSR ││ (Issued Certs) ││ (All Templates) │
+ * ├──────────────────────────────┤├──────────────────────────────┤├──────────────────────────────┤
+ * ├─────┼──────────┼─────────────┤├─────┼──────────┼─────────────┤├─────┼──────────┼─────────────┤
+ * │Time │ Operator │ Action ││Time │ Operator │ Action ││Time │ Operator │ Action │
+ * ├─────┴──────────┴─────────────┤├─────┴──────────┴─────────────┤├─────┴──────────┴─────────────┤
+ * │ (Audit Logs) ││ (Audit Logs) ││ (Audit Logs) │
+ * ├──────────────────────────────┤├──────────────────────────────┤├──────────────────────────────┤
+ * │ Ready: (Last operation) ││ Unsaved: (Last operation) ││ Ready: (Last Operation) │
+ * └──────────────────────────────┘└──────────────────────────────┘└──────────────────────────────┘
+ */
+public class MainUI extends JFrame {
+ /**
+ * Default db file (./data/ca.json)
+ */
+ private static final Path PATH_DEFAULT = Path.of("data", "ca.json");
+
+ /**
+ * The root panel (Box layout).
+ */
+ private final JPanel rootPanel = new JPanel(new BoxLayout(rootPane, BoxLayout.PAGE_AXIS));
+
+ /**
+ * Common toolbar buttons
+ */
+ private final JButton buttonToolbarLoad = btn("Load", "open.png", this::onLoad);
+ private final JButton buttonToolbarSave = btn("Save", "saveall.png", this::onSave);
+
+ /**
+ * Toolbar that switches with the tab.
+ */
+ private final JPanel panelContextAwareToolbar = new JPanel(new CardLayout(0, 0));
+
+ /**
+ * Tab root.
+ */
+ private final JTabbedPane tabbedPane = new JTabbedPane();
+
+ /**
+ * CA tab
+ */
+ private final JLabel labelCACertificate = new JLabel();
+ private final JLabel labelPrivateKey = new JLabel();
+ private final JButton buttonGenPrivKey = btn("Generate", 'G', this::onGeneratePrivateKey);
+ private final JButton buttonInstallCA = btn("Install", 'I', this::onInstallCA);
+ private final JButton buttonGenCSR = btn("CSR", this::onSignCSR);
+ private final JToolBar toolbarCA = new JToolBar();
+ private final JButton buttonCAToolbarCRL = btn("CRL", "publisher.png", this::onCRL);
+
+ /**
+ * Certs tab
+ */
+ private JPanel panelCertsTab;
+ private final JTable tableCerts = new JTable();
+ private final CertTableModel modelCerts = new CertTableModel();
+ private final JToolBar toolbarCerts = new JToolBar();
+ private final JButton buttonCertsToolbarNew = btn("Sign", "new.png", this::onIssue);
+ private final JButton buttonCertsToolbarRevoke = btn("Revoke", "deletetest.png", this::onRevokeCert);
+ private final JButton buttonCertsToolbarExport = btn("Export", "export.png", this::onExportCert);
+
+ /**
+ * Templates tab
+ */
+ private JPanel panelTmpTab;
+ private final JTable tableTemplates = new JTable();
+ private final TemplateTableModel modelTemplates = new TemplateTableModel();
+ private final JToolBar toolbarTemplates = new JToolBar();
+ private final JButton buttonTemplatesToolbarNew = btn("New", "new.png", this::onNewTemplate);
+ private final JButton buttonTemplatesToolbarEnable = btn("Enable", "enable.png", this::onEnableTemplate);
+ private final JButton buttonTemplatesToolbarDisable = btn("Disable", "disable.png", this::onDisableTemplate);
+ private final JButton buttonTemplatesToolbarDelete = btn("Delete", "deletetest.png", this::onDeleteTemplate);
+
+ /**
+ * Logs region
+ */
+ private final JPanel panelLogs;
+ private final JTable tableAuditLogs = new JTable();
+ private final LogTableModel modelAuditLogs = new LogTableModel();
+
+ /**
+ * Status region
+ */
+ private final JLabel labelStatus = new JLabel();
+ private ObservedData<Boolean> unsaved = new ObservedData<>(false, this::acceptUnsaved);
+
+ /**
+ * CA and observers
+ */
+ private CertificationAuthority ca;
+
+ private final GroupObserver obs = new GroupObserver();
+
+ /**
+ * EFFECTS: Setup the CA and GUI.
+ */
+ public MainUI() {
+ setTitle("JCA");
+ setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+ setContentPane(rootPanel);
+ rootPanel.setLayout(new BoxLayout(rootPanel, BoxLayout.PAGE_AXIS));
+
+ rootPanel.add(setupToolbar());
+ final JSplitPane splitPane = new JSplitPane(0);
+ rootPanel.add(splitPane);
+ splitPane.setLeftComponent(setupTabs());
+ rootPanel.getRootPane().setDefaultButton(buttonGenPrivKey);
+
+ splitPane.setRightComponent(panelLogs = defView(scrTbl(tableAuditLogs), "No audit logs"));
+ panelLogs.setPreferredSize(new Dimension(panelLogs.getPreferredSize().width,
+ panelLogs.getPreferredSize().height / 2));
+ panelLogs.setBackground(new Color(-1));
+
+ rootPanel.add(labelStatus);
+ labelStatus.setBorder(BorderFactory.createEmptyBorder(4, 8, 8, 8));
+
+ ca = new CertificationAuthority();
+
+ tableAuditLogs.setModel(modelAuditLogs);
+ tableCerts.setModel(modelCerts);
+ tableTemplates.setModel(modelTemplates);
+
+ tabbedPane.addChangeListener(this::onChangeTab);
+ setupObservers();
+
+ setCA(ca);
+ }
+
+ // -----BEGIN HELPER METHODS-----
+
+ /**
+ * EFFECTS: Rewind the CA and refresh all pages.
+ * MODIFIES: ca (observer), this
+ */
+ private void setCA(CertificationAuthority ca) {
+ this.ca = ca;
+ ca.registerObserver(obs);
+
+ modelAuditLogs.setPtrData(ca.getLogs());
+ modelCerts.setPtrData(ca.getSigned());
+ modelCerts.setPtrRevokedData(ca.getRevoked());
+ modelTemplates.setPtrData(ca.getTemplates());
+
+ renderRefresh();
+ }
+
+ // -----END HELPER METHODS-----
+
+ // -----BEGIN DATA OBSERVERS-----
+
+ /**
+ * EFFECTS: Setup observers
+ * MODIFIES: this
+ */
+ private void setupObservers() {
+ obs.register(AuditLogEntry.class, this::acceptAuditLog);
+ obs.register(Certificate.class, this::acceptCertificate);
+ obs.register(RSAPublicKey.class, this::acceptPrivateKey);
+ obs.register(Template.class, this::acceptTemplate);
+ }
+
+ /**
+ * EFFECTS: Handle new audit log, hide default text, notify the model
+ * MODIFIES: this
+ * REQUIRES: direction == ADD, i >= 0
+ */
+ private void acceptAuditLog(AuditLogEntry auditLogEntry, int direction, int i) {
+ setContentVisible(panelLogs, true);
+ modelAuditLogs.fireTableRowsInserted(ca.getLogs().size() - 1, ca.getLogs().size() - 1);
+ acceptUnsaved(unsaved.get(), Observer.DIRECTION_CHANGE, Observer.INDEX_NOT_IN_LIST);
+ }
+
+ /**
+ * EFFECTS: Handle CA cert or new issued cert, notify CA page or model accordingly, hide certs default text
+ * MODIFIES: this
+ * REQUIRES: direction == CHANGE or ADD, i >= 0 or -1
+ */
+ private void acceptCertificate(Certificate cert, int direction, int i) {
+ if (i == Observer.INDEX_NOT_IN_LIST) {
+ renderCAPage();
+ } else {
+ setContentVisible(panelCertsTab, true);
+ modelCerts.fireTableRowsInserted(i, i);
+ }
+ }
+
+ /**
+ * EFFECTS: Handle added, changed, or deleted template; notify model, show / hide default text.
+ * MODIFIES: this
+ * REQUIRES: i >= 0.
+ */
+ private void acceptTemplate(Template template, int direction, int i) {
+ setContentVisible(panelTmpTab, !ca.getTemplates().isEmpty());
+ switch (direction) {
+ case Observer.DIRECTION_ADD:
+ modelTemplates.fireTableRowsInserted(i, i);
+ break;
+ case Observer.DIRECTION_CHANGE:
+ modelTemplates.fireTableRowsUpdated(i, i);
+ break;
+ case Observer.DIRECTION_REMOVE:
+ modelTemplates.fireTableRowsDeleted(i, i);
+ break;
+ }
+ }
+
+ /**
+ * EFFECTS: Handle added private key. Change buttons / labels accordingly.
+ * MODIFIES: this
+ */
+ private void acceptPrivateKey(RSAPublicKey pubKey, int direction, int i) {
+ renderCAPage();
+ }
+
+ /**
+ * EFFECTS: Handle status label change, set status to unsaved / saved + latest action.
+ * MODIFIES: this
+ */
+ private void acceptUnsaved(Boolean unsaved, int direction, int i) {
+ labelStatus.setText(unsaved ? "Unsaved" : "Ready");
+ if (!ca.getLogs().isEmpty()) {
+ labelStatus.setText(labelStatus.getText() + ": " + ca.getLogs().get(ca.getLogs().size() - 1).getAction());
+ }
+ }
+
+ // -----END DATA OBSERVERS----
+
+ // -----BEGIN RENDERERS-----
+
+ /**
+ * EFFECTS: Setup the toolbar.
+ * MODIFIES: this
+ */
+ private JToolBar setupToolbar() {
+ final JToolBar toolBar = new JToolBar();
+ toolBar.setAlignmentX(Component.LEFT_ALIGNMENT);
+ toolBar.setBorder(BorderFactory.createEmptyBorder(4, 8, 4, 8));
+
+ toolBar.add(buttonToolbarLoad);
+ toolBar.add(buttonToolbarSave);
+
+ toolBar.add(panelContextAwareToolbar);
+
+ panelContextAwareToolbar.add(toolbarTemplates, "CardToolbarTemplates");
+
+ toolbarTemplates.add(Box.createHorizontalGlue());
+ toolbarTemplates.add(buttonTemplatesToolbarNew);
+ toolbarTemplates.add(buttonTemplatesToolbarEnable);
+ toolbarTemplates.add(buttonTemplatesToolbarDisable);
+ toolbarTemplates.add(buttonTemplatesToolbarDelete);
+
+ panelContextAwareToolbar.add(toolbarCerts, "CardToolbarCerts");
+ toolbarCerts.add(Box.createHorizontalGlue());
+ toolbarCerts.add(buttonCertsToolbarNew);
+ toolbarCerts.add(buttonCertsToolbarRevoke);
+ toolbarCerts.add(buttonCertsToolbarExport);
+
+ panelContextAwareToolbar.add(toolbarCA, "CardToolbarCA");
+ toolbarCA.add(Box.createHorizontalGlue());
+ toolbarCA.add(buttonCAToolbarCRL);
+ return toolBar;
+ }
+
+ /**
+ * EFFECTS: Setup the tabs
+ * MODIFIES: this
+ */
+ private JTabbedPane setupTabs() {
+ tabbedPane.setAlignmentX(Component.LEFT_ALIGNMENT);
+ tabbedPane.setBorder(BorderFactory.createEmptyBorder(8, 8, 4, 8));
+
+ final JPanel panelTabCA = new JPanel();
+ panelTabCA.setLayout(new GridBagLayout());
+ tabbedPane.addTab("CA", panelTabCA);
+
+ panelTabCA.add(new JLabel("Welcome to JCA"), new GCBuilder().anchor(WEST).insectTop(8).build());
+ panelTabCA.add(labelPrivateKey, new GCBuilder().gridY(1).anchor(WEST).build());
+ panelTabCA.add(labelCACertificate, new GCBuilder().gridY(2).anchor(WEST).build());
+ panelTabCA.add(buttonGenPrivKey, new GCBuilder().gridXY(1, 1).fill(HORIZONTAL).build());
+ panelTabCA.add(buttonInstallCA, new GCBuilder().gridXY(1, 2).fill(HORIZONTAL).build());
+ panelTabCA.add(buttonGenCSR, new GCBuilder().gridXY(2, 2).fill(HORIZONTAL).build());
+ panelTabCA.add(new JPanel(), new GCBuilder().gridXY(3, 3).expandXY().fill(BOTH).build());
+ tabbedPane.addTab("Certs", panelCertsTab = defView(scrTbl(tableCerts), "No issued certs"));
+ tabbedPane.addTab("Templates", panelTmpTab = defView(scrTbl(tableTemplates), "No templates"));
+
+ return tabbedPane;
+ }
+
+ /**
+ * EFFECTS: Render public key and CA to the CA page and toolbar
+ * MODIFIES: this
+ */
+ private void renderCAPage() {
+ if (ca.getPublicKey() == null) {
+ labelPrivateKey.setText("Private key not installed");
+ } else {
+ labelPrivateKey.setText(String.format("%s key: %s ...",
+ ca.getPublicKey().getAlgorithm(),
+ ca.getPublicKey().getModulus().toString(16).substring(0, 16)));
+ }
+ if (ca.getCertificate() == null) {
+ labelCACertificate.setText("CA certificate not installed");
+ } else {
+ labelCACertificate.setText(String.format("<html>CA: %s<br>Issued by: %s</html>",
+ ca.getCertificate().getCertificate().getSubject().toString(),
+ ca.getCertificate().getCertificate().getIssuer().toString()));
+ }
+ buttonGenPrivKey.setEnabled(ca.getPublicKey() == null);
+ buttonInstallCA.setEnabled(ca.getPublicKey() != null && ca.getCertificate() == null);
+ buttonGenCSR.setEnabled(ca.getPublicKey() != null && ca.getCertificate() == null);
+ buttonCertsToolbarNew.setEnabled(ca.getPublicKey() != null && ca.getCertificate() != null);
+ buttonCAToolbarCRL.setEnabled(ca.getPublicKey() != null && ca.getCertificate() != null);
+ }
+
+ /**
+ * EFFECTS: Reset all GUI to initial state and render the CA again.
+ * MODIFIES: this
+ */
+ private void renderRefresh() {
+ acceptUnsaved(false, Observer.DIRECTION_CHANGE, Observer.INDEX_NOT_IN_LIST);
+ onChangeTab(null);
+ renderCAPage();
+
+ modelAuditLogs.fireTableDataChanged();
+ setContentVisible(panelLogs, !ca.getLogs().isEmpty());
+
+ modelCerts.fireTableDataChanged();
+ setContentVisible(panelCertsTab, !ca.getSigned().isEmpty());
+
+ modelTemplates.fireTableDataChanged();
+ setContentVisible(panelTmpTab, !ca.getTemplates().isEmpty());
+ }
+
+ // -----END RENDERERS-----
+
+ // -----BEGIN ACTION LISTENERS-----
+
+ /**
+ * EFFECTS: Switch toolbar according to tab change.
+ * MODIFIES: this
+ */
+ private void onChangeTab(ChangeEvent ev) {
+ final CardLayout toolbarCardLayout = (CardLayout) panelContextAwareToolbar.getLayout();
+ switch (tabbedPane.getSelectedIndex()) {
+ case 0: {
+ toolbarCerts.setEnabled(false);
+ toolbarTemplates.setEnabled(false);
+ toolbarCardLayout.show(panelContextAwareToolbar, "CardToolbarCA");
+ break;
+ }
+ case 1: {
+ toolbarCerts.setEnabled(true);
+ toolbarTemplates.setEnabled(false);
+ toolbarCardLayout.show(panelContextAwareToolbar, "CardToolbarCerts");
+ break;
+ }
+ case 2: {
+ toolbarCerts.setEnabled(false);
+ toolbarTemplates.setEnabled(true);
+ toolbarCardLayout.show(panelContextAwareToolbar, "CardToolbarTemplates");
+ break;
+ }
+ }
+ }
+
+ /**
+ * EFFECTS: Generate private key.
+ * MODIFIES: this
+ * REQUIRES: No private key / CA is installed.
+ */
+ private void onGeneratePrivateKey(ActionEvent ev) {
+ try {
+ ca.generateKey();
+ unsaved.set(true);
+ } catch (NoSuchAlgorithmException e) {
+ alert(rootPanel, "Generate private key", e);
+ } finally {
+ renderCAPage();
+ }
+ }
+
+ /**
+ * EFFECTS: Sign a CSR and save to disk (in binary form).
+ * MODIFIES: this
+ * REQUIRES: Proper private key installed, no CA.
+ */
+ private void onSignCSR(ActionEvent ev) {
+ final Path p = chooseFile(rootPanel, "DER binary (*.csr)", "csr");
+ if (p == null) {
+ return;
+ }
+
+ try {
+ final OutputStream fd = Files.newOutputStream(p,
+ StandardOpenOption.WRITE,
+ StandardOpenOption.TRUNCATE_EXISTING,
+ StandardOpenOption.CREATE);
+ final CertificationRequest csr = ca.signCSR();
+ fd.write(Utils.byteToByte(csr.encodeDER()));
+ fd.close();
+ unsaved.set(true);
+ } catch (IOException | ParseException | NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {
+ alert(rootPanel, "Sign certification request", e);
+ }
+ }
+
+ /**
+ * EFFECTS: Pick a certificate and install.
+ * MODIFIES: this
+ * REQUIRES: Proper private key is installed, no CA.
+ */
+ private void onInstallCA(ActionEvent ev) {
+ final Path p = chooseFile(rootPanel, "DER X.509 certificate (*.crt, *.pem)", "crt", "pem");
+ if (p == null) {
+ return;
+ }
+
+ try {
+ final Certificate crt = new Certificate(new BytesReader(UIUtils.openDERorPEM(p, "CERTIFICATE")),
+ false);
+ ca.installCertificate(crt);
+ unsaved.set(true);
+ } catch (IOException | ParseException | InvalidCAException e) {
+ alert(rootPanel, "Install CA", e);
+ } finally {
+ renderCAPage();
+ }
+ }
+
+ /**
+ * EFFECTS: Load the database and refresh.
+ * MODIFIES: this
+ */
+ private void onLoad(ActionEvent ev) {
+ if (unsaved.get()) {
+ alert(rootPanel, "Load database from filesystem",
+ "Unable to load: current modifications are not saved.");
+ return;
+ }
+
+ try {
+ setCA(Decoder.decodeCA(FS.read(PATH_DEFAULT)));
+ } catch (NoSuchAlgorithmException | InvalidDBException e) {
+ alert(rootPanel, "Load database from filesystem", e);
+ }
+ }
+
+ /**
+ * EFFECTS: Save database.
+ * MODIFIES: this
+ */
+ private void onSave(ActionEvent ev) {
+ try {
+ FS.write(PATH_DEFAULT, Decoder.encodeCA(this.ca));
+ unsaved.set(false);
+ } catch (IOException e) {
+ alert(rootPanel, "Save database to filesystem", e);
+ }
+ }
+
+ /**
+ * EFFECTS: Enable a template.
+ * MODIFIES: this
+ */
+ private void onEnableTemplate(ActionEvent ev) {
+ if (tableTemplates.getSelectedRow() == -1) {
+ return;
+ }
+
+ final Template t = ca.getTemplates().get(tableTemplates.getSelectedRow());
+ if (t.isEnabled()) {
+ return;
+ }
+ ca.setTemplateEnable(t, true);
+ unsaved.set(true);
+ }
+
+ /**
+ * EFFECTS: Disable a template.
+ * MODIFIES: this
+ */
+ private void onDisableTemplate(ActionEvent ev) {
+ if (tableTemplates.getSelectedRow() == -1) {
+ return;
+ }
+
+ final Template t = ca.getTemplates().get(tableTemplates.getSelectedRow());
+ if (!t.isEnabled()) {
+ return;
+ }
+ ca.setTemplateEnable(t, false);
+ unsaved.set(true);
+ }
+
+ /**
+ * EFFECTS: Delete a template.
+ * MODIFIES: this
+ */
+ private void onDeleteTemplate(ActionEvent ev) {
+ if (tableTemplates.getSelectedRow() == -1) {
+ return;
+ }
+
+ final Template t = ca.getTemplates().get(tableTemplates.getSelectedRow());
+ ca.removeTemplate(t);
+ unsaved.set(true);
+ }
+
+ /**
+ * EFFECTS: Save the selected cert as a DER binary.
+ * MODIFIES: this
+ */
+ private void onExportCert(ActionEvent ev) {
+ if (tableCerts.getSelectedRow() == -1) {
+ return;
+ }
+
+ final Certificate c = ca.getSigned().get(tableCerts.getSelectedRow());
+ final Path p = chooseFile(rootPanel, "DER binary (*.crt)", "crt");
+ if (p == null) {
+ return;
+ }
+ try {
+ final OutputStream fd = Files.newOutputStream(p,
+ StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE);
+ fd.write(Utils.byteToByte(c.encodeDER()));
+ fd.close();
+ } catch (IOException e) {
+ alert(rootPanel, "Export certificate", e);
+ }
+ }
+
+ /**
+ * EFFECTS: Show revocation dialog for the selected cert. Save enforced.
+ * MODIFIES: this
+ */
+ private void onRevokeCert(ActionEvent ev) {
+ if (tableCerts.getSelectedRow() == -1) {
+ return;
+ }
+
+ final Certificate c = ca.getSigned().get(tableCerts.getSelectedRow());
+ if (ca.getRevoked().stream().anyMatch(r ->
+ r.getSerialNumber().getLong() == c.getCertificate().getSerialNumber().getLong())) {
+ return;
+ }
+ final RevokeDialog diag = new RevokeDialog(c);
+ diag.pack();
+ diag.setLocationRelativeTo(this);
+ diag.setVisible(true);
+
+ final RevokedCertificate res = diag.getRes();
+ if (res == null) {
+ return;
+ }
+
+ ca.revoke(res);
+ onSave(null);
+ }
+
+ /**
+ * EFFECTS: Sign a CRL and save to disk. Save enforced.
+ * MODIFIES: this
+ * REQUIRES: Proper private key and CA cert installed.
+ */
+ private void onCRL(ActionEvent ev) {
+ final Path p = chooseFile(rootPanel, "DER CRL (*.crl)", "crl");
+ if (p == null) {
+ return;
+ }
+ try {
+ final OutputStream fd = Files.newOutputStream(p,
+ StandardOpenOption.WRITE,
+ StandardOpenOption.TRUNCATE_EXISTING,
+ StandardOpenOption.CREATE);
+ final CertificateList crl = ca.signCRL();
+ fd.write(Utils.byteToByte(crl.encodeDER()));
+ fd.close();
+ onSave(null);
+ } catch (IOException | SignatureException | InvalidKeyException | NoSuchAlgorithmException e) {
+ alert(rootPanel, "Sign CRL", e);
+ }
+ }
+
+ /**
+ * EFFECTS: Pick a CSR, show issue dialog, sign cert. Save enforced.
+ * MODIFIES: this
+ * REQUIRES: Proper private key / CA is installed.
+ */
+ private void onIssue(ActionEvent ev) {
+ if (ca.getTemplates().stream().noneMatch(Template::isEnabled)) {
+ alert(rootPanel, "Issue new certificate", "No enabled templates.");
+ return;
+ }
+ final Path p = chooseFile(rootPanel, "DER CSR (*.csr, *.pem)", "csr", "pem");
+ if (p == null) {
+ return;
+ }
+ try {
+ CertificationRequest csr = new CertificationRequest(new BytesReader(UIUtils.openDERorPEM(p,
+ "CERTIFICATE REQUEST")), false);
+ final IssueDialog diag = new IssueDialog(csr, ca.getTemplates());
+ diag.setLocationRelativeTo(this);
+ diag.setVisible(true);
+ final Template res = diag.getRes();
+ if (res == null) {
+ return;
+ }
+ ca.signCert(csr.getCertificationRequestInfo(), res);
+ onSave(null);
+ } catch (IOException | ParseException | NoSuchAlgorithmException | SignatureException | InvalidKeyException e) {
+ alert(rootPanel, "Issue new certificate", e);
+ }
+ }
-public class MainUI {
- private JTabbedPane tabbedPane;
- private JPanel rootPanel;
- private JList listTemplates;
- private JList listCertificates;
- private JList listLogs;
- private JLabel labelStatus;
- private JButton buttonSave;
-
- public JFrame createWindow() {
- final JFrame frame = new JFrame("JCA");
- frame.setContentPane(this.rootPanel);
- frame.setVisible(true);
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.pack();
- return frame;
+ /**
+ * EFFECTS: Show the new template dialog and add a template.
+ * MODIFIES: this
+ */
+ private void onNewTemplate(ActionEvent ev) {
+ final TemplateEditDialog diag = new TemplateEditDialog(temp ->
+ ca.getTemplates().stream().anyMatch(t -> t.getName().equals(temp)));
+ diag.pack();
+ diag.setLocationRelativeTo(this);
+ diag.setVisible(true);
+ final Template res = diag.getRes();
+ if (res == null) {
+ return;
+ }
+ ca.addTemplate(res);
+ unsaved.set(true);
}
}