aboutsummaryrefslogtreecommitdiff
path: root/src/main/model/pki/cert/Extension.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/model/pki/cert/Extension.java')
-rw-r--r--src/main/model/pki/cert/Extension.java113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/main/model/pki/cert/Extension.java b/src/main/model/pki/cert/Extension.java
new file mode 100644
index 0000000..0c104a4
--- /dev/null
+++ b/src/main/model/pki/cert/Extension.java
@@ -0,0 +1,113 @@
+package model.pki.cert;
+
+import model.asn1.*;
+import model.asn1.exceptions.ParseException;
+import model.asn1.parsing.BytesReader;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.stream.Stream;
+
+/**
+ * A X.509v3 certificate extension entry.
+ * <pre>
+ * Extension ::= SEQUENCE {
+ * extnId EXTENSION.&id({ExtensionSet}),
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING
+ * (CONTAINING EXTENSION.&ExtnType({ExtensionSet}{@extnId})
+ * ENCODED BY der),
+ * ... }
+ * </pre>
+ * Extensions only exist in v3 certificates. They allow the CA and the relying party to add additional verification
+ * stages to the certificate to constraint its use or to supply additional information. For example, the CA may put a
+ * CDP (CRL Distribution Point) into the extensions.
+ */
+public class Extension extends ASN1Object {
+ /**
+ * The ID of the type of that extension.
+ */
+ private final ObjectIdentifier extnId;
+
+ /**
+ * Marking an extension critical means that the relying-party
+ * must reject that certificate if the type is unrecognized.
+ * If the type is recognized but cannot be fully parsed, the
+ * behaviour is undefined.
+ * Marking an extension critical reduces compatibility.
+ */
+ private final Bool critical;
+
+ /**
+ * The DER-encoded ASN.1 content of that extension.
+ */
+ private final OctetString extnValue;
+
+ /**
+ * EFFECTS: Init with tags, extnId, critical, and extnValue. For tags, see {@link ASN1Object}.
+ * extnValue is not checked against extnId.
+ * REQUIRES: Tags of extnId, critical, extnValue should be OID, BOOLEAN, OCTET STRING. The value should be a DER
+ * bytes octet string. If critical is unspecified (which defaults to false), put null.
+ */
+ public Extension(Tag tag, Tag parentTag,
+ final ObjectIdentifier extnId,
+ final Bool critical,
+ final OctetString extnValue) {
+ super(tag, parentTag);
+ this.extnId = extnId;
+ this.critical = critical;
+ this.extnValue = extnValue;
+ }
+
+ /**
+ * EFFECTS: Parse input DER.
+ * Throws {@link ParseException} if the input is invalid:
+ * - Any fields missing
+ * - Any fields having an incorrect tag (as seen in the ASN.1 definition)
+ * - Any fields with encoding instructions that violate implicit / explicit encoding rules
+ * - Other issues found during parsing the object, like early EOF (see {@link ASN1Object})
+ * Note that critical is optional, and if it does not exist, it will be left as null, and it should be treated as
+ * false.
+ * MODIFIES: this, encoded
+ */
+ public Extension(BytesReader encoded, boolean hasParentType) throws ParseException {
+ super(encoded, hasParentType);
+ this.extnId = new ObjectIdentifier(encoded, false);
+ this.extnId.getTag().enforce(ObjectIdentifier.TAG);
+
+ if (encoded.detectTag(Bool.TAG)) {
+ critical = new Bool(encoded, false);
+ } else {
+ critical = null;
+ }
+
+ this.extnValue = new OctetString(encoded, false);
+ this.extnValue.getTag().enforce(OctetString.TAG);
+ }
+
+ /**
+ * EFFECTS: Encode the DER.
+ */
+ @Override
+ public Byte[] encodeValueDER() {
+ return Stream.of(Arrays.asList(extnId.encodeDER()),
+ critical == null ? Collections.<Byte>emptyList() :
+ Arrays.asList(critical.encodeDER()),
+ Arrays.asList(extnValue.encodeDER()))
+ .flatMap(Collection::stream)
+ .toArray(Byte[]::new);
+ }
+
+ public ObjectIdentifier getExtnId() {
+ return extnId;
+ }
+
+ public Bool getCritical() {
+ return critical;
+ }
+
+ public OctetString getExtnValue() {
+ return extnValue;
+ }
+}