package model.pki; import annotations.Assoc; import model.asn1.ASN1Object; import model.asn1.ObjectIdentifier; import model.asn1.Tag; 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; /** * Implements the following: *
 *   AlgorithmIdentifier{ALGORITHM:SupportedAlgorithms} ::= SEQUENCE {
 *       algorithm ALGORITHM.&id({SupportedAlgorithms}),
 *       parameters ALGORITHM.&Type({SupportedAlgorithms}{@algorithm}) OPTIONAL,
 *   ... }
 * 
*/ public class AlgorithmIdentifier extends ASN1Object { /** * The type of that attribute. For example,
1.2.840.113549.1.1.11
is sha256WithRSAEncryption. */ @Assoc(partOf = true) private final ObjectIdentifier type; /** * Additional parameters for that algorithm. Optional, and could be ASN.1 NULL or Java null (absent). * According to RFC8017$A.2, it should be NULL for a number of algorithms: *
     *     PKCS1Algorithms    ALGORITHM-IDENTIFIER ::= {
     *        { OID rsaEncryption                PARAMETERS NULL } |
     *        { OID md2WithRSAEncryption         PARAMETERS NULL } |
     *        { OID md5WithRSAEncryption         PARAMETERS NULL } |
     *        { OID sha1WithRSAEncryption        PARAMETERS NULL } |
     *        { OID sha224WithRSAEncryption      PARAMETERS NULL } |
     *        { OID sha256WithRSAEncryption      PARAMETERS NULL } |
     *        { OID sha384WithRSAEncryption      PARAMETERS NULL } |
     *        { OID sha512WithRSAEncryption      PARAMETERS NULL } |
     *        { OID sha512-224WithRSAEncryption  PARAMETERS NULL } |
     *        { OID sha512-256WithRSAEncryption  PARAMETERS NULL } |
     *        { OID id-RSAES-OAEP   PARAMETERS RSAES-OAEP-params } |
     *        PKCS1PSourceAlgorithms                               |
     *        { OID id-RSASSA-PSS   PARAMETERS RSASSA-PSS-params },
     *        ...  -- Allows for future expansion --
     *    }
     * 
*/ @Assoc(partOf = true, lowerBond = 0) private final ASN1Object parameters; /** * EFFECT: Init the object with tag, parentTag, type, and parameters. For tag and parentTag, see {@link ASN1Object}. * REQUIRES: The values must match the type. Type tag should be UNIVERSAL OID. Parameters nullable. */ public AlgorithmIdentifier(Tag tag, Tag parentTag, ObjectIdentifier type, ASN1Object parameters) { super(tag, parentTag); this.type = type; this.parameters = parameters; } /** * EFFECTS: Parse input DER. Parameters are not checked against the type. * Throws {@link ASN1Object} if 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}) * MODIFIES: this, encoded */ public AlgorithmIdentifier(BytesReader encoded, boolean hasParentTag) throws ParseException { super(encoded, hasParentTag); int i = encoded.getIndex(); this.type = new ObjectIdentifier(encoded, false); this.type.getTag().enforce(ObjectIdentifier.TAG); i = encoded.getIndex() - i; if (getLength() > i) { this.parameters = ASN1Object.parse(encoded, false); } else { this.parameters = null; } } /** * EFFECTS: Encode the fields into DER, in the order. */ @Override public Byte[] encodeValueDER() { return Stream.of(Arrays.asList(type.encodeDER()), parameters == null ? Collections.emptyList() : Arrays.asList(parameters.encodeDER())) .flatMap(Collection::stream) .toArray(Byte[]::new); } public ObjectIdentifier getType() { return type; } public ASN1Object getParameters() { return parameters; } }