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