aboutsummaryrefslogtreecommitdiff
path: root/src/main/model/ca/CertificationAuthority.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/model/ca/CertificationAuthority.java')
-rw-r--r--src/main/model/ca/CertificationAuthority.java94
1 files changed, 69 insertions, 25 deletions
diff --git a/src/main/model/ca/CertificationAuthority.java b/src/main/model/ca/CertificationAuthority.java
index 038d209..5181f1a 100644
--- a/src/main/model/ca/CertificationAuthority.java
+++ b/src/main/model/ca/CertificationAuthority.java
@@ -1,5 +1,6 @@
package model.ca;
+import model.Observer;
import model.asn1.*;
import model.asn1.exceptions.InvalidCAException;
import model.asn1.exceptions.ParseException;
@@ -28,11 +29,12 @@ import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.time.ZoneId;
import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Stream;
/**
- * Holds a CA private key, its certificate, signed / revoked list, template list, and logs list.
+ * Holds a CA private key, its certificate, signed / revoked list, template list, and logs list. Data can be observed.
*/
public class CertificationAuthority {
public static final int SERIAL_DEFAULT = 1;
@@ -83,7 +85,12 @@ public class CertificationAuthority {
private final String user;
/**
- * EFFECT: Init with the given parameters and user "yuuta".
+ * Data observers.
+ */
+ private final List<Observer> observers;
+
+ /**
+ * EFFECT: Init with the given parameters, user "yuuta", and no observers.
* Throws {@link NoSuchAlgorithmException} if the key is specified but RSA is not supported.
* Throws {@link InvalidKeySpecException} if the key specified is invalid.
* Throws {@link InvalidCAException} or {@link ParseException} if the CA specified is invalid.
@@ -111,11 +118,12 @@ public class CertificationAuthority {
this.templates = new ArrayList<>(templates);
this.logs = new ArrayList<>(logs);
this.user = "yuuta";
+ this.observers = new ArrayList<>();
}
/**
* EFFECT: Init with a null key and null certificate, empty signed, revoked template, and log list,
- * serial at SERIAL_DEFAULT, and user "yuuta".
+ * serial at SERIAL_DEFAULT, user "yuuta", and no observers.
*/
public CertificationAuthority() {
this.key = null;
@@ -127,10 +135,13 @@ public class CertificationAuthority {
this.templates = new ArrayList<>();
this.logs = new ArrayList<>();
this.user = "yuuta";
+ this.observers = new ArrayList<>();
}
/**
* EFFECTS: Generate a new RSA2048 private key. This action will be logged.
+ * Observers will be notified for (RSAPublicKey.class, DIRECTION_CHANGE, INDEX_NOT_IN_LIST).
+ * Observers will be notified for (AuditLogEntry.class, DIRECTION_ADD, i).
* REQUIRES: getPublicKey() is null (i.e., no private key had been installed)
* MODIFIES: this
*/
@@ -140,6 +151,7 @@ public class CertificationAuthority {
final KeyPair pair = gen.generateKeyPair();
this.key = (RSAPrivateKey) pair.getPrivate();
this.publicKey = (RSAPublicKey) pair.getPublic();
+ notif(getPublicKey(), Observer.DIRECTION_CHANGE, Observer.INDEX_NOT_IN_LIST);
log("Generated CA private key.");
}
@@ -159,6 +171,8 @@ public class CertificationAuthority {
/**
* EFFECTS: Load the RSA private and public exponents. This action will be logged.
+ * Observers will be notified for (RSAPublicKey.class, DIRECTION_CHANGE, INDEX_NOT_IN_LIST).
+ * Observers will be notified for (AuditLogEntry.class, DIRECTION_ADD, i).
* Throws {@link NoSuchAlgorithmException} if RSA is not available on the platform.
* Throws {@link InvalidKeySpecException} if the input is invalid.
* REQUIRES: getPublicKey() is null (i.e., no private key had been installed)
@@ -167,6 +181,7 @@ public class CertificationAuthority {
public void loadKey(BigInteger n, BigInteger p, BigInteger e)
throws NoSuchAlgorithmException, InvalidKeySpecException {
setKey(n, p, e);
+ notif(getPublicKey(), Observer.DIRECTION_CHANGE, Observer.INDEX_NOT_IN_LIST);
log("Installed CA private key.");
}
@@ -252,6 +267,8 @@ public class CertificationAuthority {
* - The new certificate must have the same algorithm and public key as getPublicKey()
* - It must have basicConstraints { cA = TRUE }
* - It must contain key usage Digital Signature, Certificate Sign, CRL Sign
+ * Observers will be notified for (Certificate.class, DIRECTION_CHANGE, INDEX_NOT_IN_LIST).
+ * Observers will be notified for (AuditLogEntry.class, DIRECTION_ADD, i).
* Throws {@link ParseException} if the cert has invalid extension values.
* This action will be logged.
* REQUIRES:
@@ -261,6 +278,7 @@ public class CertificationAuthority {
public void installCertificate(Certificate certificate) throws InvalidCAException, ParseException {
validateCertificate(certificate);
this.certificate = certificate;
+ notif(certificate, Observer.DIRECTION_CHANGE, Observer.INDEX_NOT_IN_LIST);
log("CA certificate is installed.");
}
@@ -325,6 +343,7 @@ public class CertificationAuthority {
/**
* EFFECT: Generate CSR and sign it, so the CA can request itself a certificate.
+ * Observers will be notified for (AuditLogEntry.class, DIRECTION_ADD, i).
* REQUIRES: The CA cert must not be installed.
* MODIFIES: this (This action will be logged)
*/
@@ -351,6 +370,8 @@ public class CertificationAuthority {
/**
* EFFECTS: Sign the CSR based on the template.
+ * Observers will be notified for (Certificate.class, DIRECTION_ADD, i).
+ * Observers will be notified for (AuditLogEntry.class, DIRECTION_ADD, i).
* REQUIRES: The CA cert must be installed first, req must have a subject, template must be enabled.
* MODIFIES: this
*/
@@ -363,7 +384,8 @@ public class CertificationAuthority {
new BitString(BitString.TAG, null, 0,
signBytes(newCert.encodeValueDER())));
this.signed.add(cert);
- log("Signed a cert with serial number " + cert.getCertificate().getSerialNumber());
+ notif(cert, Observer.DIRECTION_ADD, this.signed.size() - 1);
+ log("Signed a cert with serial number " + cert.getCertificate().getSerialNumber().getLong());
return cert;
}
@@ -406,17 +428,22 @@ public class CertificationAuthority {
/**
* EFFECTS: Add the revocation info to revoked list. This action will be logged.
+ * Observers will be notified for (RevokedCertificate.class, DIRECTION_ADD, i).
+ * Observers will be notified for (AuditLogEntry.class, DIRECTION_ADD, i).
* REQUIRES: revoked should have the serial of an issued certificate; its date should be current.
* MODIFIES: this
*/
public void revoke(RevokedCertificate rev) {
revoked.add(rev);
- log("Certificate " + rev.getSerialNumber().getLong() + " is revoked with reason " + rev.getReason());
+ notif(rev, Observer.DIRECTION_ADD, revoked.size() - 1);
+ log("Certificate " + rev.getSerialNumber().getLong() + " is revoked with reason " + rev.getReason()
+ + " at " + rev.getRevocationDate().getTimestamp().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
}
/**
* EFFECTS: Generate and sign the CRL, based on getRevokedCerts(). The CSR will have current time as thisUpdate with
* no nextUptime, and it will have issuer same as the CA's subject.
+ * Observers will be notified for (AuditLogEntry.class, DIRECTION_ADD, i).
* REQUIRES: The CA cert must be installed first.
* MODIFIES: this (This action will be logged)
*/
@@ -439,10 +466,29 @@ public class CertificationAuthority {
/**
* EFFECTS: Log the action with the current date and user.
+ * Observers will be notified for (AuditLogEntry.class, DIRECTION_ADD, i).
* MODIFIES: this
*/
private void log(String message) {
- this.logs.add(new AuditLogEntry(user, ZonedDateTime.now(), message));
+ final AuditLogEntry i = new AuditLogEntry(user, ZonedDateTime.now(), message);
+ this.logs.add(i);
+ notif(i, Observer.DIRECTION_ADD, logs.size() - 1);
+ }
+
+ /**
+ * EFFECTS: Register the given observer, so it will be called upon changes.
+ * MODIFIES: this
+ */
+ public void registerObserver(final Observer<?> observer) {
+ this.observers.add(observer);
+ }
+
+ /**
+ * EFFECTS: Notify the observers.
+ * REQUIRES: direction must be valid Observer constants, i must be either >= 0 or Observer.INDEX_NOT_IN_LIST.
+ */
+ private void notif(Object o, int direction, int i) {
+ observers.forEach(e -> e.accept(o, direction, i));
}
/**
@@ -460,33 +506,43 @@ public class CertificationAuthority {
/**
* EFFECTS: Install the new template. This action will be logged.
+ * Observers will be notified for (Template.class, DIRECTION_ADD, i).
+ * Observers will be notified for (AuditLogEntry.class, DIRECTION_ADD, i).
* REQUIRES: findTemplate(template.getName(), false) == null
* MODIFIES: this
*/
public void addTemplate(Template template) {
this.templates.add(template);
+ notif(template, Observer.DIRECTION_ADD, templates.size() - 1);
log("Added a new template: " + template.getName());
}
/**
- * EFFECTS: Set the given template to enabled / disabled. This action will be logged.
+ * EFFECTS: Set the given template to enabled / disabled, order will be kept. This action will be logged.
+ * Observers will be notified for (Template.class, DIRECTION_CHANGE, i).
+ * Observers will be notified for (AuditLogEntry.class, DIRECTION_ADD, i).
* REQUIRES: the template is valid (findTemplate does not return null)
* MODIFIES: this
*/
public void setTemplateEnable(Template template, boolean enable) {
final Template t = findTemplate(template.getName(), false);
- templates.remove(t);
- templates.add(new Template(t.getName(), enable, t.getSubject(), t.getValidity()));
+ int i = templates.indexOf(t);
+ templates.set(i, new Template(t.getName(), enable, t.getSubject(), t.getValidity()));
+ notif(template, Observer.DIRECTION_CHANGE, i);
log("Template " + template.getName() + " has been " + (enable ? "enabled" : "disabled"));
}
/**
* EFFECTS: Remove the given template. This action will be logged.
+ * Observers will be notified for (Template.class, DIRECTION_REMOVE, i).
+ * Observers will be notified for (AuditLogEntry.class, DIRECTION_ADD, i).
* REQUIRES: the template is valid (findTemplate does not return null)
* MODIFIES: this
*/
public void removeTemplate(Template template) {
+ int i = templates.indexOf(template);
templates.remove(findTemplate(template.getName(), false));
+ notif(template, Observer.DIRECTION_REMOVE, i);
log("Template " + template.getName() + " is removed");
}
@@ -496,40 +552,28 @@ public class CertificationAuthority {
return certificate;
}
- /**
- * EFFECT: Get a read-only view of the signed certificates.
- */
public List<Certificate> getSigned() {
- return List.copyOf(signed);
+ return signed;
}
- /**
- * EFFECT: Get a read-only view of the revoked certificates.
- */
public List<RevokedCertificate> getRevoked() {
- return List.copyOf(revoked);
+ return revoked;
}
public int getSerial() {
return serial;
}
- /**
- * EFFECT: Get a read-only view of the templates.
- */
public List<Template> getTemplates() {
- return List.copyOf(templates);
+ return templates;
}
public String getUser() {
return user;
}
- /**
- * EFFECT: Get a read-only view of the logs.
- */
public List<AuditLogEntry> getLogs() {
- return List.copyOf(logs);
+ return logs;
}
public RSAPublicKey getPublicKey() {