using System; using Org.BouncyCastle.Utilities; namespace Org.BouncyCastle.Asn1 { /** * 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 : Asn1Object, Asn1TaggedObjectParser { internal int tagNo; // internal bool empty; internal bool explicitly = true; internal Asn1Encodable obj; static public Asn1TaggedObject GetInstance( Asn1TaggedObject obj, bool explicitly) { if (explicitly) { return (Asn1TaggedObject) obj.GetObject(); } throw new ArgumentException("implicitly tagged tagged object"); } static public Asn1TaggedObject GetInstance( object obj) { if (obj == null || obj is Asn1TaggedObject) { return (Asn1TaggedObject) obj; } throw new ArgumentException("Unknown object in GetInstance: " + obj.GetType().FullName, "obj"); } /** * @param tagNo the tag number for this object. * @param obj the tagged object. */ protected Asn1TaggedObject( int tagNo, Asn1Encodable obj) { this.explicitly = true; this.tagNo = tagNo; this.obj = obj; } /** * @param explicitly true if the object is explicitly tagged. * @param tagNo the tag number for this object. * @param obj the tagged object. */ protected Asn1TaggedObject( bool explicitly, int tagNo, Asn1Encodable obj) { // IAsn1Choice marker interface 'insists' on explicit tagging this.explicitly = explicitly || (obj is IAsn1Choice); this.tagNo = tagNo; this.obj = obj; } protected override bool Asn1Equals( Asn1Object asn1Object) { Asn1TaggedObject other = asn1Object as Asn1TaggedObject; if (other == null) return false; return this.tagNo == other.tagNo // && this.empty == other.empty && this.explicitly == other.explicitly // TODO Should this be part of equality? && Platform.Equals(GetObject(), other.GetObject()); } protected override int Asn1GetHashCode() { int code = tagNo.GetHashCode(); // 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... // code ^= explicitly.GetHashCode(); if (obj != null) { code ^= obj.GetHashCode(); } return code; } public int TagNo { get { return tagNo; } } /** * return whether or not the object may be explicitly tagged. *

* 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 bool IsExplicit() { return explicitly; } public bool IsEmpty() { return false; //empty; } /** * return whatever was following the tag. *

* 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 Asn1Object GetObject() { if (obj != null) { return obj.ToAsn1Object(); } 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 IAsn1Convertible GetObjectParser( int tag, bool isExplicit) { switch (tag) { case Asn1Tags.Set: return Asn1Set.GetInstance(this, isExplicit).Parser; case Asn1Tags.Sequence: return Asn1Sequence.GetInstance(this, isExplicit).Parser; case Asn1Tags.OctetString: return Asn1OctetString.GetInstance(this, isExplicit).Parser; } if (isExplicit) { return GetObject(); } throw Platform.CreateNotImplementedException("implicit tagging for tag: " + tag); } public override string ToString() { return "[" + tagNo + "]" + obj; } } }