From d342a45d98c4795b3a3fe1aaef5236ad4a782b55 Mon Sep 17 00:00:00 2001 From: Yuuta Liang Date: Thu, 12 Oct 2023 12:10:33 +0800 Subject: Implement data structures from X.680, X.501, X.509, and PKCS#10, with X.690 encoding / decoding support The implementation took four days, and it is still a little bit rough. Updated version should arrive soon. Signed-off-by: Yuuta Liang --- src/main/model/pki/cert/Extension.java | 113 +++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/main/model/pki/cert/Extension.java (limited to 'src/main/model/pki/cert/Extension.java') 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. + *
+ *     Extension ::= SEQUENCE {
+ *      extnId EXTENSION.&id({ExtensionSet}),
+ *      critical BOOLEAN DEFAULT FALSE,
+ *      extnValue OCTET STRING
+ *          (CONTAINING EXTENSION.&ExtnType({ExtensionSet}{@extnId})
+ *              ENCODED BY der),
+ *     ... }
+ * 
+ * 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.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; + } +} -- cgit v1.2.3