aboutsummaryrefslogtreecommitdiff
path: root/src/main/ui
diff options
context:
space:
mode:
authorYuuta Liang <yuutaw@student.cs.ubc.ca>2023-10-25 03:30:45 +0800
committerYuuta Liang <yuutaw@student.cs.ubc.ca>2023-10-25 03:30:45 +0800
commitd7ff9d5e217873609d79efe279f2634e3a3dd8b4 (patch)
tree704729e5eed658728b521acd407c6ca767f7e865 /src/main/ui
parent55df54e5dbf26e6824123410784d00aa793c3781 (diff)
downloadjca-d7ff9d5e217873609d79efe279f2634e3a3dd8b4.tar
jca-d7ff9d5e217873609d79efe279f2634e3a3dd8b4.tar.gz
jca-d7ff9d5e217873609d79efe279f2634e3a3dd8b4.tar.bz2
jca-d7ff9d5e217873609d79efe279f2634e3a3dd8b4.zip
Refactor: move all logics into CertificationAuthority
Signed-off-by: Yuuta Liang <yuutaw@student.cs.ubc.ca>
Diffstat (limited to 'src/main/ui')
-rw-r--r--src/main/ui/IssueScreen.java22
-rw-r--r--src/main/ui/JCA.java73
-rw-r--r--src/main/ui/MainScreen.java4
-rw-r--r--src/main/ui/MgmtScreen.java117
-rw-r--r--src/main/ui/TemplateSetScreen.java13
-rw-r--r--src/main/ui/TemplatesScreen.java17
-rw-r--r--src/main/ui/Utils.java14
7 files changed, 73 insertions, 187 deletions
diff --git a/src/main/ui/IssueScreen.java b/src/main/ui/IssueScreen.java
index 8376146..5e3ad50 100644
--- a/src/main/ui/IssueScreen.java
+++ b/src/main/ui/IssueScreen.java
@@ -66,7 +66,6 @@ public class IssueScreen implements UIHandler {
try {
Certificate certificate = session.getCa().signCert(incomingCSR.getCertificationRequestInfo(), template);
System.out.println(Utils.toPEM(certificate.encodeDER(), "CERTIFICATE"));
- session.log("A certificate was issued.");
session.setScreen(Screen.MAIN);
} catch (Throwable e) {
System.out.println(e.getMessage());
@@ -75,11 +74,11 @@ public class IssueScreen implements UIHandler {
/**
* EFFECTS: Set or unset the subject.
- * MODIFIES: template
+ * MODIFIES: this
*/
private void handleIssueSetSubject(String val) {
try {
- template.setSubject(val);
+ template = new Template(template.getName(), template.isEnabled(), val, template.getValidity());
} catch (ParseException e) {
System.out.println(e.getMessage());
}
@@ -87,7 +86,7 @@ public class IssueScreen implements UIHandler {
/**
* EFFECTS: Set or unset the validity.
- * MODIFIES: template
+ * MODIFIES: this
*/
private void handleIssueSetValidity(String val) {
if (val == null) {
@@ -100,7 +99,7 @@ public class IssueScreen implements UIHandler {
System.out.println("Invalid validity days");
return;
}
- template.setValidity(i);
+ template = new Template(template.getName(), template.isEnabled(), template.getSubject(), i);
} catch (NumberFormatException ignored) {
System.out.println("Invalid validity days");
}
@@ -108,7 +107,7 @@ public class IssueScreen implements UIHandler {
/**
* EFFECTS: Handle the set command.
- * MODIFIES: template
+ * MODIFIES: this
*/
private void handleIssueSet(String... args) {
if (args.length != 2 && args.length != 3) {
@@ -132,13 +131,10 @@ public class IssueScreen implements UIHandler {
@Override
public void command(String... args) {
- switch (args[0]) {
- case "set":
- handleIssueSet(args);
- break;
- default:
- help();
- break;
+ if (args[0].equals("set")) {
+ handleIssueSet(args);
+ } else {
+ help();
}
}
diff --git a/src/main/ui/JCA.java b/src/main/ui/JCA.java
index 7892850..882c546 100644
--- a/src/main/ui/JCA.java
+++ b/src/main/ui/JCA.java
@@ -1,16 +1,11 @@
package ui;
import model.asn1.exceptions.ParseException;
-import model.ca.AuditLogEntry;
-import model.ca.CACertificate;
-import model.ca.Template;
+import model.ca.CertificationAuthority;
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
-import java.time.ZonedDateTime;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
+import java.security.spec.InvalidKeySpecException;
import java.util.Scanner;
/**
@@ -26,31 +21,19 @@ public class JCA {
private final UIHandler templatesScreen;
private final UIHandler templateSetScreen;
/**
- * Templates
- */
- private final List<Template> templates;
- /**
* The CA
*/
- private final CACertificate ca;
- /**
- * Audit logs
- */
- private final List<AuditLogEntry> logs;
- /**
- * Current user
- */
- private final String user;
+ private final CertificationAuthority ca;
/**
* The current screen.
*/
private UIHandler screen;
/**
- * EFFECTS: Init with main screen, empty templates, logs, user 'yuuta', and generate a private key with no CA cert.
+ * EFFECTS: Init with main screen and empty CA. No private key and no CA cert.
* Throws {@link NoSuchAlgorithmException} when crypto issue happens.
*/
- public JCA() throws NoSuchAlgorithmException {
+ public JCA() throws NoSuchAlgorithmException, InvalidKeySpecException {
this.mainScreen = new MainScreen(this);
this.mgmtScreen = new MgmtScreen(this);
this.issueScreen = new IssueScreen(this);
@@ -59,12 +42,7 @@ public class JCA {
setScreen(Screen.MAIN);
- this.templates = new ArrayList<>();
- this.ca = new CACertificate();
- this.logs = new ArrayList<>();
- this.user = "yuuta";
-
- this.ca.generateKey();
+ this.ca = new CertificationAuthority();
}
/**
@@ -73,10 +51,10 @@ public class JCA {
*/
public boolean checkCA(boolean requireInstalled) {
if (requireInstalled && ca.getCertificate() == null) {
- System.out.println("The CA is not installed yet");
+ System.out.println("No CA installed");
return false;
} else if (!requireInstalled && ca.getCertificate() != null) {
- System.out.println("The CA is already installed");
+ System.out.println("CA already installed");
return false;
}
return true;
@@ -101,19 +79,6 @@ public class JCA {
}
/**
- * EFFECTS: Find the template based on name, or null if not found.
- */
- public Template findTemplate(String name, boolean requireEnabled) {
- Optional<Template> opt = templates.stream().filter(temp -> {
- if (requireEnabled && !temp.isEnabled()) {
- return false;
- }
- return temp.getName().equals(name);
- }).findFirst();
- return opt.orElse(null);
- }
-
- /**
* EFFECT: Set the current screen with optional args. Exit the program when mode is null.
* MODIFIES: this
*/
@@ -143,7 +108,7 @@ public class JCA {
private void handleLine(String... args) {
if (args[0].equals("log")) {
- getLogs().forEach(System.out::println);
+ ca.getLogs().forEach(System.out::println);
return;
}
switch (args[0]) {
@@ -168,15 +133,7 @@ public class JCA {
}
private void printPS1() {
- System.out.printf("%s@JCA %s ", user, screen.getPS1());
- }
-
- /**
- * EFFECT: Log an action to the audit log
- * MODIFIES: this
- */
- public void log(String action) {
- this.logs.add(new AuditLogEntry(user, ZonedDateTime.now(), action));
+ System.out.printf("%s@JCA %s ", ca.getUser(), screen.getPS1());
}
/**
@@ -195,15 +152,7 @@ public class JCA {
}
}
- public List<Template> getTemplates() {
- return templates;
- }
-
- public CACertificate getCa() {
+ public CertificationAuthority getCa() {
return ca;
}
-
- public List<AuditLogEntry> getLogs() {
- return logs;
- }
}
diff --git a/src/main/ui/MainScreen.java b/src/main/ui/MainScreen.java
index b6e4372..2eaf882 100644
--- a/src/main/ui/MainScreen.java
+++ b/src/main/ui/MainScreen.java
@@ -86,7 +86,7 @@ public class MainScreen implements UIHandler {
System.out.println("Usage: issue <template>");
return;
}
- Template tmp = session.findTemplate(args[1], true);
+ Template tmp = session.getCa().findTemplate(args[1], true);
if (tmp == null) {
System.out.println("Cannot find the template specified");
return;
@@ -138,7 +138,6 @@ public class MainScreen implements UIHandler {
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");
}
@@ -179,7 +178,6 @@ public class MainScreen implements UIHandler {
}
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());
}
diff --git a/src/main/ui/MgmtScreen.java b/src/main/ui/MgmtScreen.java
index 1957c7e..0a25bfe 100644
--- a/src/main/ui/MgmtScreen.java
+++ b/src/main/ui/MgmtScreen.java
@@ -1,20 +1,14 @@
package ui;
-import model.asn1.ASN1Object;
-import model.asn1.BitString;
-import model.asn1.Bool;
-import model.asn1.ObjectIdentifier;
+import model.asn1.exceptions.InvalidCAException;
import model.asn1.exceptions.ParseException;
import model.asn1.parsing.BytesReader;
import model.csr.CertificationRequest;
-import model.pki.SubjectPublicKeyInfo;
import model.pki.cert.Certificate;
-import model.pki.cert.Extension;
import model.pki.cert.TbsCertificate;
-import java.util.Arrays;
+import java.security.NoSuchAlgorithmException;
import java.util.Base64;
-import java.util.BitSet;
/**
* Manage the private key and CA certificate. It can print the public key, generate CSR, and install CA cert.
@@ -35,6 +29,7 @@ public class MgmtScreen implements UIHandler {
@Override
public void help() {
System.out.print("show\tView the public key and CA certificate\n"
+ + "genkey\tGenerate a RSA private key\n"
+ "csr\tGenerate a CSR for a upper-level CA to sign\n"
+ "install\tInstall a CA certificate\n"
+ "exit\tGo to main menu\n"
@@ -46,8 +41,14 @@ public class MgmtScreen implements UIHandler {
*/
@Override
public void show() {
- System.out.printf("Public Key:\t%s\n",
- Base64.getEncoder().encodeToString(session.getCa().getPublicKey().getEncoded()));
+ if (session.getCa().getPublicKey() == null) {
+ System.out.println("No private key installed");
+ } else {
+ System.out.println("Public Key (RSA2048):");
+ System.out.printf("\tModules:\t\t%s\n", session.getCa().getPublicKey().getModulus().toString(10));
+ System.out.printf("\tPublic Exponent:\t%s\n",
+ session.getCa().getPublicKey().getPublicExponent().toString(16));
+ }
if (!session.checkCA(true)) {
return;
}
@@ -63,6 +64,7 @@ public class MgmtScreen implements UIHandler {
/**
* EFFECT: Generate a CSR
+ * MODIFIES: session
*/
private void handleCSR() {
if (!session.checkCA(false)) {
@@ -71,80 +73,14 @@ public class MgmtScreen implements UIHandler {
try {
CertificationRequest req = session.getCa().signCSR();
System.out.println(Utils.toPEM(req.encodeDER(), "CERTIFICATE REQUEST"));
- session.log("Signed CA CSR.");
} catch (Throwable e) {
System.out.println(e.getMessage());
}
}
/**
- * EFFECTS: Throw {@link ParseException} if the incoming cert is not v3.
- */
- private void validateCACertificateVersion(Certificate cert) throws ParseException {
- if (cert.getCertificate().getVersion() == null
- || cert.getCertificate().getVersion().getLong() != TbsCertificate.VERSION_V3) {
- throw new ParseException("The input certificate must be V3");
- }
- }
-
- /**
- * EFFECTS: Throw {@link ParseException} if the incoming cert does not have the matching public key.
- */
- private void validateCACertificatePublicKey(Certificate cert) throws ParseException {
- final SubjectPublicKeyInfo expectedPKInfo = session.getCa().getCAPublicKeyInfo();
- if (!Arrays.equals(cert.getCertificate().getSubjectPublicKeyInfo().getAlgorithm().getType().getInts(),
- expectedPKInfo.getAlgorithm().getType().getInts())
- || !Arrays.equals(cert.getCertificate().getSubjectPublicKeyInfo().getSubjectPublicKey().getVal(),
- expectedPKInfo.getSubjectPublicKey().getVal())) {
- throw new ParseException("The input certificate does not have the corresponding public key");
- }
- }
-
- /**
- * EFFECTS: Throw {@link ParseException} if the incoming cert does not have cA = true in its basicConstraints.
- */
- private void validateCACertificateBasicConstraints(Certificate cert) throws ParseException {
- final Extension basicConstraints = cert.getCertificate().getExtension(ObjectIdentifier.OID_BASIC_CONSTRAINTS);
- if (basicConstraints == null
- || basicConstraints.getExtnValue().getBytes().length <= 0) {
- throw new ParseException("The certificate does not have a valid basicConstraints extension.");
- }
- final ASN1Object basicConstraintsValue =
- new ASN1Object(new BytesReader(basicConstraints.getExtnValue().getBytes()), false);
- if (basicConstraintsValue.getLength() <= 0) {
- throw new ParseException("The certificate does not have a valid basicConstraints extension.");
- }
- final ASN1Object bool =
- ASN1Object.parse(new BytesReader(basicConstraintsValue.encodeValueDER()), false);
- if (!(bool instanceof Bool)
- || !((Bool) bool).getValue()) {
- throw new ParseException("The certificate does not have a valid basicConstraints extension.");
- }
- }
-
- /**
- * EFFECTS: Throw {@link ParseException} if the incoming cert does not have valid key usages.
- */
- private void validateCACertificateKeyUsage(Certificate cert) throws ParseException {
- final Extension keyUsage = cert.getCertificate().getExtension(ObjectIdentifier.OID_KEY_USAGE);
- if (keyUsage == null
- || keyUsage.getExtnValue().getBytes().length <= 0) {
- throw new ParseException("The certificate does not have a valid keyUsage extension.");
- }
- final ASN1Object keyUsageValue =
- ASN1Object.parse(new BytesReader(keyUsage.getExtnValue().getBytes()), false);
- if (keyUsageValue.getLength() <= 0
- || !(keyUsageValue instanceof BitString)) {
- throw new ParseException("The certificate does not have a valid keyUsage extension.");
- }
- final BitSet bitSet = BitSet.valueOf(Utils.byteToByte(((BitString) keyUsageValue).getVal()));
- if (!bitSet.get(7) || !bitSet.get(2) || !bitSet.get(1)) {
- throw new ParseException("The certificate does not have a valid keyUsage extension.");
- }
- }
-
- /**
* EFFECTS: Handle the 'install' command. Read incoming certificate and validate it.
+ * MODIFIES: session
*/
private void handleInstall() {
if (!session.checkCA(false)) {
@@ -152,14 +88,24 @@ public class MgmtScreen implements UIHandler {
}
try {
final Byte[] in = session.handleInputPEM("CERTIFICATE");
- Certificate cert = new Certificate(new BytesReader(in), false);
- validateCACertificateVersion(cert);
- validateCACertificatePublicKey(cert);
- validateCACertificateBasicConstraints(cert);
- validateCACertificateKeyUsage(cert);
+ final Certificate cert = new Certificate(new BytesReader(in), false);
session.getCa().installCertificate(cert);
- session.log("A CA certificate is installed.");
- } catch (ParseException e) {
+ } catch (InvalidCAException | ParseException e) {
+ System.out.println(e.getMessage());
+ }
+ }
+
+ /**
+ * EFFECTS: Handle the 'genkey' command. Generate a RSA2048 private key.
+ * MODIFIES: session
+ */
+ private void handleGenKey() {
+ if (session.getCa().getPublicKey() != null) {
+ System.out.println("A private key is already installed.");
+ }
+ try {
+ session.getCa().generateKey();
+ } catch (NoSuchAlgorithmException e) {
System.out.println(e.getMessage());
}
}
@@ -170,6 +116,9 @@ public class MgmtScreen implements UIHandler {
@Override
public void command(String... args) {
switch (args[0]) {
+ case "genkey":
+ handleGenKey();
+ break;
case "csr":
handleCSR();
break;
diff --git a/src/main/ui/TemplateSetScreen.java b/src/main/ui/TemplateSetScreen.java
index 42f393b..a0b39c1 100644
--- a/src/main/ui/TemplateSetScreen.java
+++ b/src/main/ui/TemplateSetScreen.java
@@ -32,11 +32,11 @@ public class TemplateSetScreen implements UIHandler {
/**
* EFFECTS: Parse and set / unset the subject of the template
- * MODIFIES: this#template
+ * MODIFIES: this
*/
private void handleSetSubject(String val) {
try {
- template.setSubject(val);
+ template = new Template(template.getName(), template.isEnabled(), val, template.getValidity());
} catch (ParseException e) {
System.out.println(e.getMessage());
}
@@ -44,7 +44,7 @@ public class TemplateSetScreen implements UIHandler {
/**
* EFFECTS: Set the validity of the template to the given integer
- * MODIFIES: this#template
+ * MODIFIES: this
*/
private void handleSetValidity(String val) {
if (val == null) {
@@ -57,7 +57,7 @@ public class TemplateSetScreen implements UIHandler {
System.out.println("Invalid validity days");
return;
}
- template.setValidity(i);
+ template = new Template(template.getName(), template.isEnabled(), template.getSubject(), i);
} catch (NumberFormatException ignored) {
System.out.println("Invalid validity days");
}
@@ -65,7 +65,7 @@ public class TemplateSetScreen implements UIHandler {
/**
* EFFECTS: Handle the `set` command.
- * MODIFIES: this#template
+ * MODIFIES: this
*/
private void handleSet(String... args) {
if (args.length != 2 && args.length != 3) {
@@ -93,9 +93,8 @@ public class TemplateSetScreen implements UIHandler {
*/
@Override
public void commit() {
- session.getTemplates().add(template);
+ session.getCa().addTemplate(template);
session.setScreen(Screen.TEMPLATES);
- session.log("A new template is added.");
}
/**
diff --git a/src/main/ui/TemplatesScreen.java b/src/main/ui/TemplatesScreen.java
index 3bdbebe..e08df50 100644
--- a/src/main/ui/TemplatesScreen.java
+++ b/src/main/ui/TemplatesScreen.java
@@ -1,6 +1,7 @@
package ui;
import model.ca.Template;
+import model.x501.Name;
/**
* The screen that allows users to list templates and manage them.
@@ -34,7 +35,7 @@ public class TemplatesScreen implements UIHandler {
*/
@Override
public void show() {
- session.getTemplates().forEach(tem ->
+ session.getCa().getTemplates().forEach(tem ->
System.out.printf("%s[%s]\t%s\t%d Days\n",
tem.getName(),
tem.isEnabled() ? "ENABLED" : "DISABLED",
@@ -50,13 +51,13 @@ public class TemplatesScreen implements UIHandler {
System.out.println("Usage: add <name>");
return;
}
- if (session.findTemplate(args[1], false) != null) {
+ if (session.getCa().findTemplate(args[1], false) != null) {
System.out.println("The template already exists.");
return;
}
session.setScreen(Screen.TEMPLATE_SET,
- new Template(args[1], false, null, 30));
+ new Template(args[1], false, (Name) null, 30));
}
/**
@@ -68,13 +69,12 @@ public class TemplatesScreen implements UIHandler {
System.out.printf("Usage: %s <template>\n", enable ? "enable" : "disable");
return;
}
- Template tmp = session.findTemplate(args[1], false);
+ Template tmp = session.getCa().findTemplate(args[1], false);
if (tmp == null) {
System.out.println("Cannot find the template specified");
return;
}
- tmp.setEnabled(enable);
- session.log("A template was enabled / disabled.");
+ session.getCa().setTemplateEnable(tmp, enable);
}
/**
@@ -86,13 +86,12 @@ public class TemplatesScreen implements UIHandler {
System.out.println("Usage: delete <template>");
return;
}
- Template tmp = session.findTemplate(args[1], true);
+ Template tmp = session.getCa().findTemplate(args[1], true);
if (tmp == null) {
System.out.println("Cannot find the template specified");
return;
}
- session.getTemplates().remove(tmp);
- session.log("A template was deleted.");
+ session.getCa().removeTemplate(tmp);
}
/**
diff --git a/src/main/ui/Utils.java b/src/main/ui/Utils.java
index 6841536..f653ffa 100644
--- a/src/main/ui/Utils.java
+++ b/src/main/ui/Utils.java
@@ -88,14 +88,10 @@ public final class Utils {
* REQUIRES: desiredTag must be upper case and not empty.
*/
public static String toPEM(Byte[] input, String tag) {
- StringBuilder builder = new StringBuilder();
- builder.append("-----BEGIN ");
- builder.append(tag);
- builder.append("-----\n");
- builder.append(Base64.getEncoder().encodeToString(byteToByte(input)));
- builder.append("\n-----END ");
- builder.append(tag);
- builder.append("-----");
- return builder.toString();
+ return "-----BEGIN " + tag + "-----\n"
+ + Base64.getEncoder().encodeToString(byteToByte(input))
+ + "\n-----END "
+ + tag
+ + "-----";
}
}