org.bouncycastle.asn1.ASN1Sequence Maven / Gradle / Ivy
Show all versions of bcprov-jdk14 Show documentation
package org.bouncycastle.asn1; import java.io.IOException; import java.util.Enumeration; import java.util.Iterator; import java.util.NoSuchElementException; import org.bouncycastle.util.Arrays; /** * ASN.1 SEQUENCE
and SEQUENCE OF constructs. ** DER form is always definite form length fields, while * BER support uses indefinite form. * *
X.690
*8: Basic encoding rules
*8.9 Encoding of a sequence value
* 8.9.1 The encoding of a sequence value shall be constructed. ** 8.9.2 The contents octets shall consist of the complete * encoding of one data value from each of the types listed in * the ASN.1 definition of the sequence type, in the order of * their appearance in the definition, unless the type was referenced * with the keyword OPTIONAL or the keyword DEFAULT. *
* 8.9.3 The encoding of a data value may, but need not, * be present for a type which was referenced with the keyword * OPTIONAL or the keyword DEFAULT. * If present, it shall appear in the encoding at the point * corresponding to the appearance of the type in the ASN.1 definition. *
* 8.10 Encoding of a sequence-of value *
* 8.10.1 The encoding of a sequence-of value shall be constructed. *
* 8.10.2 The contents octets shall consist of zero, * one or more complete encodings of data values from the type listed in * the ASN.1 definition. *
* 8.10.3 The order of the encodings of the data values shall be * the same as the order of the data values in the sequence-of value to * be encoded. *
*9: Canonical encoding rules
*9.1 Length forms
* If the encoding is constructed, it shall employ the indefinite-length form. * If the encoding is primitive, it shall include the fewest length octets necessary. * [Contrast with 8.1.3.2 b).] * *11: Restrictions on BER employed by both CER and DER
*11.5 Set and sequence components with default value
** The encoding of a set value or sequence value shall not include * an encoding for any component value which is equal to * its default value. *
*/ public abstract class ASN1Sequence extends ASN1Primitive implements org.bouncycastle.util.Iterable { static final ASN1UniversalType TYPE = new ASN1UniversalType(ASN1Sequence.class, BERTags.SEQUENCE) { ASN1Primitive fromImplicitConstructed(ASN1Sequence sequence) { return sequence; } }; /** * Return an ASN1Sequence from the given object. * * @param obj the object we want converted. * @exception IllegalArgumentException if the object cannot be converted. * @return an ASN1Sequence instance, or null. */ public static ASN1Sequence getInstance(Object obj) { if (obj == null || obj instanceof ASN1Sequence) { return (ASN1Sequence)obj; } // else if (obj instanceof ASN1SequenceParser) else if (obj instanceof ASN1Encodable) { ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); if (primitive instanceof ASN1Sequence) { return (ASN1Sequence)primitive; } } else if (obj instanceof byte[]) { try { return (ASN1Sequence)TYPE.fromByteArray((byte[])obj); } catch (IOException e) { throw new IllegalArgumentException("failed to construct sequence from byte[]: " + e.getMessage()); } } throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); } /** * Return an ASN1 SEQUENCE from a tagged object. There is a special * case here, if an object appears to have been explicitly tagged on * reading but we were expecting it to be implicitly tagged in the * normal course of events it indicates that we lost the surrounding * sequence - so we need to add it back (this will happen if the tagged * object is a sequence that contains other sequences). If you are * dealing with implicitly tagged sequences you really should * be using this method. * * @param taggedObject the tagged object. * @param explicit true if the object is meant to be explicitly tagged, * false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. * @return an ASN1Sequence instance. */ public static ASN1Sequence getInstance(ASN1TaggedObject taggedObject, boolean explicit) { return (ASN1Sequence)TYPE.getContextInstance(taggedObject, explicit); } // NOTE: Only non-final to support LazyEncodedSequence ASN1Encodable[] elements; /** * Create an empty SEQUENCE */ protected ASN1Sequence() { this.elements = ASN1EncodableVector.EMPTY_ELEMENTS; } /** * Create a SEQUENCE containing one object. * @param element the object to be put in the SEQUENCE. */ protected ASN1Sequence(ASN1Encodable element) { if (null == element) { throw new NullPointerException("'element' cannot be null"); } this.elements = new ASN1Encodable[]{ element }; } /** * Create a SEQUENCE containing a vector of objects. * @param elementVector the vector of objects to be put in the SEQUENCE. */ protected ASN1Sequence(ASN1EncodableVector elementVector) { if (null == elementVector) { throw new NullPointerException("'elementVector' cannot be null"); } this.elements = elementVector.takeElements(); } /** * Create a SEQUENCE containing an array of objects. * @param elements the array of objects to be put in the SEQUENCE. */ protected ASN1Sequence(ASN1Encodable[] elements) { if (Arrays.isNullOrContainsNull(elements)) { throw new NullPointerException("'elements' cannot be null, or contain null"); } this.elements = ASN1EncodableVector.cloneElements(elements); } ASN1Sequence(ASN1Encodable[] elements, boolean clone) { this.elements = clone ? ASN1EncodableVector.cloneElements(elements) : elements; } public ASN1Encodable[] toArray() { return ASN1EncodableVector.cloneElements(elements); } ASN1Encodable[] toArrayInternal() { return elements; } public Enumeration getObjects() { return new Enumeration() { private int pos = 0; public boolean hasMoreElements() { return pos < elements.length; } public Object nextElement() { if (pos < elements.length) { return elements[pos++]; } throw new NoSuchElementException(); } }; } public ASN1SequenceParser parser() { // NOTE: Call size() here to 'force' a LazyEncodedSequence final int count = size(); return new ASN1SequenceParser() { private int pos = 0; public ASN1Encodable readObject() throws IOException { if (count == pos) { return null; } ASN1Encodable obj = elements[pos++]; if (obj instanceof ASN1Sequence) { return ((ASN1Sequence)obj).parser(); } if (obj instanceof ASN1Set) { return ((ASN1Set)obj).parser(); } return obj; } public ASN1Primitive getLoadedObject() { return ASN1Sequence.this; } public ASN1Primitive toASN1Primitive() { return ASN1Sequence.this; } }; } /** * Return the object at the sequence position indicated by index. * * @param index the sequence number (starting at zero) of the object * @return the object at the sequence position indicated by index. */ public ASN1Encodable getObjectAt(int index) { return elements[index]; } /** * Return the number of objects in this sequence. * * @return the number of objects in this sequence. */ public int size() { return elements.length; } public int hashCode() { // return Arrays.hashCode(elements); int i = elements.length; int hc = i + 1; while (--i >= 0) { hc *= 257; hc ^= elements[i].toASN1Primitive().hashCode(); } return hc; } boolean asn1Equals(ASN1Primitive other) { if (!(other instanceof ASN1Sequence)) { return false; } ASN1Sequence that = (ASN1Sequence)other; // NOTE: Call size() here (on both) to 'force' a LazyEncodedSequence int count = this.size(); if (that.size() != count) { return false; } for (int i = 0; i < count; ++i) { ASN1Primitive p1 = this.elements[i].toASN1Primitive(); ASN1Primitive p2 = that.elements[i].toASN1Primitive(); if (p1 != p2 && !p1.asn1Equals(p2)) { return false; } } return true; } /** * Change current SEQUENCE object to be encoded as {@link DERSequence}. * This is part of Distinguished Encoding Rules form serialization. */ ASN1Primitive toDERObject() { return new DERSequence(elements, false); } /** * Change current SEQUENCE object to be encoded as {@link DLSequence}. * This is part of Direct Length form serialization. */ ASN1Primitive toDLObject() { return new DLSequence(elements, false); } abstract ASN1BitString toASN1BitString(); abstract ASN1External toASN1External(); abstract ASN1OctetString toASN1OctetString(); abstract ASN1Set toASN1Set(); boolean encodeConstructed() { return true; } public String toString() { // NOTE: Call size() here to 'force' a LazyEncodedSequence int count = size(); if (0 == count) { return "[]"; } StringBuffer sb = new StringBuffer(); sb.append('['); for (int i = 0;;) { sb.append(elements[i]); if (++i >= count) { break; } sb.append(", "); } sb.append(']'); return sb.toString(); } public Iterator iterator() { return new Arrays.Iterator (elements); } ASN1BitString[] getConstructedBitStrings() { // NOTE: Call size() here to 'force' a LazyEncodedSequence int count = size(); ASN1BitString[] bitStrings = new ASN1BitString[count]; for (int i = 0; i < count; ++i) { bitStrings[i] = ASN1BitString.getInstance(elements[i]); } return bitStrings; } ASN1OctetString[] getConstructedOctetStrings() { // NOTE: Call size() here to 'force' a LazyEncodedSequence int count = size(); ASN1OctetString[] octetStrings = new ASN1OctetString[count]; for (int i = 0; i < count; ++i) { octetStrings[i] = ASN1OctetString.getInstance(elements[i]); } return octetStrings; } }