package model.csr; import model.asn1.ASN1Object; import model.asn1.Encodable; import model.asn1.Tag; import model.asn1.exceptions.ParseException; import model.asn1.parsing.BytesReader; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; /** * Represents a CSR attribute values list. *
 *   Attribute { ATTRIBUTE:IOSet } ::= SEQUENCE {
 *       type   ATTRIBUTE.&id({IOSet}),
 *       values SET SIZE(1..MAX) OF ATTRIBUTE.&Type({IOSet}{@type})
 *   }
 * 
* Values can be none or any length. Parsing and decoding the values are handled in specific types. */ public class Values extends ASN1Object { private final ASN1Object[] array; /** * EFFECT: Initialize the list with the given tag, parentTag, and array. For tag and parentTag, consult * {@link ASN1Object}. * REQUIRES: All elements in the array shall be the same ASN.1 type. */ public Values(Tag tag, Tag parentTag, ASN1Object[] array) { super(tag, parentTag); this.array = array; } /** * EFFECT: Parse the list from input DER bytes. For details on parsing, refer to {@link ASN1Object}. * Throws {@link ParseException} for invalid input. * MODIFIES: this, encoded */ public Values(BytesReader encoded, boolean hasParentTag) throws ParseException { super(encoded, hasParentTag); final List list = new ArrayList<>(); for (int i = 0; i < getLength();) { int index = encoded.getIndex(); final ASN1Object value = ASN1Object.parse(encoded, false); list.add(value); index = encoded.getIndex() - index; i += index; } this.array = list.toArray(new ASN1Object[0]); } /** * EFFECTS: Encode the SET OF into DER, keep order. Values will be encoded one-by-one. */ @Override public Byte[] encodeValueDER() { return Stream.of(array) .map(Encodable::encodeDER) .flatMap(Arrays::stream) .toArray(Byte[]::new); } public ASN1Object[] getArray() { return array; } }