• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 ASN1Primitive
12     implements ASN1TaggedObjectParser
13 {
14     int             tagNo;
15     boolean         empty = false;
16     boolean         explicit = true;
17     ASN1Encodable obj = null;
18 
getInstance( ASN1TaggedObject obj, boolean explicit)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 
getInstance( Object obj)31     static public ASN1TaggedObject getInstance(
32         Object obj)
33     {
34         if (obj == null || obj instanceof ASN1TaggedObject)
35         {
36                 return (ASN1TaggedObject)obj;
37         }
38         else if (obj instanceof byte[])
39         {
40             try
41             {
42                 return ASN1TaggedObject.getInstance(fromByteArray((byte[])obj));
43             }
44             catch (IOException e)
45             {
46                 throw new IllegalArgumentException("failed to construct tagged object from byte[]: " + e.getMessage());
47             }
48         }
49 
50         throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName());
51     }
52 
53     /**
54      * Create a tagged object with the style given by the value of explicit.
55      * <p>
56      * If the object implements ASN1Choice the tag style will always be changed
57      * to explicit in accordance with the ASN.1 encoding rules.
58      * </p>
59      * @param explicit true if the object is explicitly tagged.
60      * @param tagNo the tag number for this object.
61      * @param obj the tagged object.
62      */
ASN1TaggedObject( boolean explicit, int tagNo, ASN1Encodable obj)63     public ASN1TaggedObject(
64         boolean         explicit,
65         int             tagNo,
66         ASN1Encodable   obj)
67     {
68         if (obj instanceof ASN1Choice)
69         {
70             this.explicit = true;
71         }
72         else
73         {
74             this.explicit = explicit;
75         }
76 
77         this.tagNo = tagNo;
78 
79         if (this.explicit)
80         {
81             this.obj = obj;
82         }
83         else
84         {
85             ASN1Primitive prim = obj.toASN1Primitive();
86 
87             if (prim instanceof ASN1Set)
88             {
89                 ASN1Set s = null;
90             }
91 
92             this.obj = obj;
93         }
94     }
95 
asn1Equals( ASN1Primitive o)96     boolean asn1Equals(
97         ASN1Primitive o)
98     {
99         if (!(o instanceof ASN1TaggedObject))
100         {
101             return false;
102         }
103 
104         ASN1TaggedObject other = (ASN1TaggedObject)o;
105 
106         if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit)
107         {
108             return false;
109         }
110 
111         if(obj == null)
112         {
113             if (other.obj != null)
114             {
115                 return false;
116             }
117         }
118         else
119         {
120             if (!(obj.toASN1Primitive().equals(other.obj.toASN1Primitive())))
121             {
122                 return false;
123             }
124         }
125 
126         return true;
127     }
128 
hashCode()129     public int hashCode()
130     {
131         int code = tagNo;
132 
133         // TODO: actually this is wrong - the problem is that a re-encoded
134         // object may end up with a different hashCode due to implicit
135         // tagging. As implicit tagging is ambiguous if a sequence is involved
136         // it seems the only correct method for both equals and hashCode is to
137         // compare the encodings...
138         if (obj != null)
139         {
140             code ^= obj.hashCode();
141         }
142 
143         return code;
144     }
145 
146     /**
147      * Return the tag number associated with this object.
148      *
149      * @return the tag number.
150      */
getTagNo()151     public int getTagNo()
152     {
153         return tagNo;
154     }
155 
156     /**
157      * return whether or not the object may be explicitly tagged.
158      * <p>
159      * Note: if the object has been read from an input stream, the only
160      * time you can be sure if isExplicit is returning the true state of
161      * affairs is if it returns false. An implicitly tagged object may appear
162      * to be explicitly tagged, so you need to understand the context under
163      * which the reading was done as well, see getObject below.
164      */
isExplicit()165     public boolean isExplicit()
166     {
167         return explicit;
168     }
169 
isEmpty()170     public boolean isEmpty()
171     {
172         return empty;
173     }
174 
175     /**
176      * return whatever was following the tag.
177      * <p>
178      * Note: tagged objects are generally context dependent if you're
179      * trying to extract a tagged object you should be going via the
180      * appropriate getInstance method.
181      */
getObject()182     public ASN1Primitive getObject()
183     {
184         if (obj != null)
185         {
186             return obj.toASN1Primitive();
187         }
188 
189         return null;
190     }
191 
192     /**
193      * Return the object held in this tagged object as a parser assuming it has
194      * the type of the passed in tag. If the object doesn't have a parser
195      * associated with it, the base object is returned.
196      */
getObjectParser( int tag, boolean isExplicit)197     public ASN1Encodable getObjectParser(
198         int     tag,
199         boolean isExplicit)
200         throws IOException
201     {
202         switch (tag)
203         {
204         case BERTags.SET:
205             return ASN1Set.getInstance(this, isExplicit).parser();
206         case BERTags.SEQUENCE:
207             return ASN1Sequence.getInstance(this, isExplicit).parser();
208         case BERTags.OCTET_STRING:
209             return ASN1OctetString.getInstance(this, isExplicit).parser();
210         }
211 
212         if (isExplicit)
213         {
214             return getObject();
215         }
216 
217         throw new ASN1Exception("implicit tagging not implemented for tag: " + tag);
218     }
219 
getLoadedObject()220     public ASN1Primitive getLoadedObject()
221     {
222         return this.toASN1Primitive();
223     }
224 
toDERObject()225     ASN1Primitive toDERObject()
226     {
227         return new DERTaggedObject(explicit, tagNo, obj);
228     }
229 
toDLObject()230     ASN1Primitive toDLObject()
231     {
232         return new DLTaggedObject(explicit, tagNo, obj);
233     }
234 
encode(ASN1OutputStream out)235     abstract void encode(ASN1OutputStream out)
236         throws IOException;
237 
toString()238     public String toString()
239     {
240         return "[" + tagNo + "]" + obj;
241     }
242 }
243