diff options
Diffstat (limited to 'core/src/main/java/org/spongycastle/asn1/ASN1TaggedObject.java')
-rw-r--r-- | core/src/main/java/org/spongycastle/asn1/ASN1TaggedObject.java | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/core/src/main/java/org/spongycastle/asn1/ASN1TaggedObject.java b/core/src/main/java/org/spongycastle/asn1/ASN1TaggedObject.java new file mode 100644 index 00000000..af778816 --- /dev/null +++ b/core/src/main/java/org/spongycastle/asn1/ASN1TaggedObject.java @@ -0,0 +1,236 @@ +package org.spongycastle.asn1; + +import java.io.IOException; + +/** + * ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by + * a [n] where n is some number - these are assumed to follow the construction + * rules (as with sequences). + */ +public abstract class ASN1TaggedObject + extends ASN1Primitive + implements ASN1TaggedObjectParser +{ + int tagNo; + boolean empty = false; + boolean explicit = true; + ASN1Encodable obj = null; + + static public ASN1TaggedObject getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + if (explicit) + { + return (ASN1TaggedObject)obj.getObject(); + } + + throw new IllegalArgumentException("implicitly tagged tagged object"); + } + + static public ASN1TaggedObject getInstance( + Object obj) + { + if (obj == null || obj instanceof ASN1TaggedObject) + { + return (ASN1TaggedObject)obj; + } + else if (obj instanceof byte[]) + { + try + { + return ASN1TaggedObject.getInstance(fromByteArray((byte[])obj)); + } + catch (IOException e) + { + throw new IllegalArgumentException("failed to construct tagged object from byte[]: " + e.getMessage()); + } + } + + throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + } + + /** + * Create a tagged object with the style given by the value of explicit. + * <p> + * If the object implements ASN1Choice the tag style will always be changed + * to explicit in accordance with the ASN.1 encoding rules. + * </p> + * @param explicit true if the object is explicitly tagged. + * @param tagNo the tag number for this object. + * @param obj the tagged object. + */ + public ASN1TaggedObject( + boolean explicit, + int tagNo, + ASN1Encodable obj) + { + if (obj instanceof ASN1Choice) + { + this.explicit = true; + } + else + { + this.explicit = explicit; + } + + this.tagNo = tagNo; + + if (this.explicit) + { + this.obj = obj; + } + else + { + ASN1Primitive prim = obj.toASN1Primitive(); + + if (prim instanceof ASN1Set) + { + ASN1Set s = null; + } + + this.obj = obj; + } + } + + boolean asn1Equals( + ASN1Primitive o) + { + if (!(o instanceof ASN1TaggedObject)) + { + return false; + } + + ASN1TaggedObject other = (ASN1TaggedObject)o; + + if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit) + { + return false; + } + + if(obj == null) + { + if (other.obj != null) + { + return false; + } + } + else + { + if (!(obj.toASN1Primitive().equals(other.obj.toASN1Primitive()))) + { + return false; + } + } + + return true; + } + + public int hashCode() + { + int code = tagNo; + + // TODO: actually this is wrong - the problem is that a re-encoded + // object may end up with a different hashCode due to implicit + // tagging. As implicit tagging is ambiguous if a sequence is involved + // it seems the only correct method for both equals and hashCode is to + // compare the encodings... + if (obj != null) + { + code ^= obj.hashCode(); + } + + return code; + } + + public int getTagNo() + { + return tagNo; + } + + /** + * return whether or not the object may be explicitly tagged. + * <p> + * Note: if the object has been read from an input stream, the only + * time you can be sure if isExplicit is returning the true state of + * affairs is if it returns false. An implicitly tagged object may appear + * to be explicitly tagged, so you need to understand the context under + * which the reading was done as well, see getObject below. + */ + public boolean isExplicit() + { + return explicit; + } + + public boolean isEmpty() + { + return empty; + } + + /** + * return whatever was following the tag. + * <p> + * Note: tagged objects are generally context dependent if you're + * trying to extract a tagged object you should be going via the + * appropriate getInstance method. + */ + public ASN1Primitive getObject() + { + if (obj != null) + { + return obj.toASN1Primitive(); + } + + return null; + } + + /** + * Return the object held in this tagged object as a parser assuming it has + * the type of the passed in tag. If the object doesn't have a parser + * associated with it, the base object is returned. + */ + public ASN1Encodable getObjectParser( + int tag, + boolean isExplicit) + { + switch (tag) + { + case BERTags.SET: + return ASN1Set.getInstance(this, isExplicit).parser(); + case BERTags.SEQUENCE: + return ASN1Sequence.getInstance(this, isExplicit).parser(); + case BERTags.OCTET_STRING: + return ASN1OctetString.getInstance(this, isExplicit).parser(); + } + + if (isExplicit) + { + return getObject(); + } + + throw new RuntimeException("implicit tagging not implemented for tag: " + tag); + } + + public ASN1Primitive getLoadedObject() + { + return this.toASN1Primitive(); + } + + ASN1Primitive toDERObject() + { + return new DERTaggedObject(explicit, tagNo, obj); + } + + ASN1Primitive toDLObject() + { + return new DLTaggedObject(explicit, tagNo, obj); + } + + abstract void encode(ASN1OutputStream out) + throws IOException; + + public String toString() + { + return "[" + tagNo + "]" + obj; + } +} |