Home | History | Annotate | Download | only in asn1
      1 package org.bouncycastle.asn1;
      2 
      3 import java.io.IOException;
      4 
      5 /**
      6  * ASN.1 TaggedObject - in ASN.1 notation this is any object preceded by
      7  * a [n] where n is some number - these are assumed to follow the construction
      8  * rules (as with sequences).
      9  */
     10 public abstract class ASN1TaggedObject
     11     extends ASN1Object
     12     implements ASN1TaggedObjectParser
     13 {
     14     int             tagNo;
     15     boolean         empty = false;
     16     boolean         explicit = true;
     17     DEREncodable    obj = null;
     18 
     19     static public ASN1TaggedObject getInstance(
     20         ASN1TaggedObject    obj,
     21         boolean             explicit)
     22     {
     23         if (explicit)
     24         {
     25             return (ASN1TaggedObject)obj.getObject();
     26         }
     27 
     28         throw new IllegalArgumentException("implicitly tagged tagged object");
     29     }
     30 
     31     static public ASN1TaggedObject getInstance(
     32         Object obj)
     33     {
     34         if (obj == null || obj instanceof ASN1TaggedObject)
     35         {
     36                 return (ASN1TaggedObject)obj;
     37         }
     38 
     39         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
     40     }
     41 
     42     /**
     43      * Create a tagged object in the explicit style.
     44      *
     45      * @param tagNo the tag number for this object.
     46      * @param obj the tagged object.
     47      */
     48     public ASN1TaggedObject(
     49         int             tagNo,
     50         DEREncodable    obj)
     51     {
     52         this.explicit = true;
     53         this.tagNo = tagNo;
     54         this.obj = obj;
     55     }
     56 
     57     /**
     58      * Create a tagged object with the style given by the value of explicit.
     59      * <p>
     60      * If the object implements ASN1Choice the tag style will always be changed
     61      * to explicit in accordance with the ASN.1 encoding rules.
     62      * </p>
     63      * @param explicit true if the object is explicitly tagged.
     64      * @param tagNo the tag number for this object.
     65      * @param obj the tagged object.
     66      */
     67     public ASN1TaggedObject(
     68         boolean         explicit,
     69         int             tagNo,
     70         DEREncodable    obj)
     71     {
     72         if (obj instanceof ASN1Choice)
     73         {
     74             this.explicit = true;
     75         }
     76         else
     77         {
     78             this.explicit = explicit;
     79         }
     80 
     81         this.tagNo = tagNo;
     82         this.obj = obj;
     83     }
     84 
     85     boolean asn1Equals(
     86         DERObject o)
     87     {
     88         if (!(o instanceof ASN1TaggedObject))
     89         {
     90             return false;
     91         }
     92 
     93         ASN1TaggedObject other = (ASN1TaggedObject)o;
     94 
     95         if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit)
     96         {
     97             return false;
     98         }
     99 
    100         if(obj == null)
    101         {
    102             if (other.obj != null)
    103             {
    104                 return false;
    105             }
    106         }
    107         else
    108         {
    109             if (!(obj.getDERObject().equals(other.obj.getDERObject())))
    110             {
    111                 return false;
    112             }
    113         }
    114 
    115         return true;
    116     }
    117 
    118     public int hashCode()
    119     {
    120         int code = tagNo;
    121 
    122         // TODO: actually this is wrong - the problem is that a re-encoded
    123         // object may end up with a different hashCode due to implicit
    124         // tagging. As implicit tagging is ambiguous if a sequence is involved
    125         // it seems the only correct method for both equals and hashCode is to
    126         // compare the encodings...
    127         if (obj != null)
    128         {
    129             code ^= obj.hashCode();
    130         }
    131 
    132         return code;
    133     }
    134 
    135     public int getTagNo()
    136     {
    137         return tagNo;
    138     }
    139 
    140     /**
    141      * return whether or not the object may be explicitly tagged.
    142      * <p>
    143      * Note: if the object has been read from an input stream, the only
    144      * time you can be sure if isExplicit is returning the true state of
    145      * affairs is if it returns false. An implicitly tagged object may appear
    146      * to be explicitly tagged, so you need to understand the context under
    147      * which the reading was done as well, see getObject below.
    148      */
    149     public boolean isExplicit()
    150     {
    151         return explicit;
    152     }
    153 
    154     public boolean isEmpty()
    155     {
    156         return empty;
    157     }
    158 
    159     /**
    160      * return whatever was following the tag.
    161      * <p>
    162      * Note: tagged objects are generally context dependent if you're
    163      * trying to extract a tagged object you should be going via the
    164      * appropriate getInstance method.
    165      */
    166     public DERObject getObject()
    167     {
    168         if (obj != null)
    169         {
    170             return obj.getDERObject();
    171         }
    172 
    173         return null;
    174     }
    175 
    176     /**
    177      * Return the object held in this tagged object as a parser assuming it has
    178      * the type of the passed in tag. If the object doesn't have a parser
    179      * associated with it, the base object is returned.
    180      */
    181     public DEREncodable getObjectParser(
    182         int     tag,
    183         boolean isExplicit)
    184     {
    185         switch (tag)
    186         {
    187         case DERTags.SET:
    188             return ASN1Set.getInstance(this, isExplicit).parser();
    189         case DERTags.SEQUENCE:
    190             return ASN1Sequence.getInstance(this, isExplicit).parser();
    191         case DERTags.OCTET_STRING:
    192             return ASN1OctetString.getInstance(this, isExplicit).parser();
    193         }
    194 
    195         if (isExplicit)
    196         {
    197             return getObject();
    198         }
    199 
    200         throw new RuntimeException("implicit tagging not implemented for tag: " + tag);
    201     }
    202 
    203     abstract void encode(DEROutputStream  out)
    204         throws IOException;
    205 
    206     public String toString()
    207     {
    208         return "[" + tagNo + "]" + obj;
    209     }
    210 }
    211