1package org.bouncycastle.asn1.x509;
2
3import java.util.Enumeration;
4import java.util.Hashtable;
5import java.util.Vector;
6
7import org.bouncycastle.asn1.ASN1Encodable;
8import org.bouncycastle.asn1.ASN1EncodableVector;
9import org.bouncycastle.asn1.ASN1Object;
10import org.bouncycastle.asn1.ASN1ObjectIdentifier;
11import org.bouncycastle.asn1.ASN1Primitive;
12import org.bouncycastle.asn1.ASN1Sequence;
13import org.bouncycastle.asn1.ASN1TaggedObject;
14import org.bouncycastle.asn1.DERSequence;
15
16public class Extensions
17    extends ASN1Object
18{
19    private Hashtable extensions = new Hashtable();
20    private Vector ordering = new Vector();
21
22    public static Extensions getInstance(
23        ASN1TaggedObject obj,
24        boolean explicit)
25    {
26        return getInstance(ASN1Sequence.getInstance(obj, explicit));
27    }
28
29    public static Extensions getInstance(
30        Object obj)
31    {
32        if (obj instanceof Extensions)
33        {
34            return (Extensions)obj;
35        }
36        else if (obj != null)
37        {
38            return new Extensions(ASN1Sequence.getInstance(obj));
39        }
40
41        return null;
42    }
43
44    /**
45     * Constructor from ASN1Sequence.
46     * <p>
47     * The extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString)
48     * </p>
49     */
50    private Extensions(
51        ASN1Sequence seq)
52    {
53        Enumeration e = seq.getObjects();
54
55        while (e.hasMoreElements())
56        {
57            Extension ext = Extension.getInstance(e.nextElement());
58
59            extensions.put(ext.getExtnId(), ext);
60            ordering.addElement(ext.getExtnId());
61        }
62    }
63
64    /**
65     * Base Constructor
66     *
67     * @param extension a single extension.
68     */
69    public Extensions(
70        Extension extension)
71    {
72        this.ordering.addElement(extension.getExtnId());
73        this.extensions.put(extension.getExtnId(), extension);
74    }
75
76    /**
77     * Base Constructor
78     *
79     * @param extensions an array of extensions.
80     */
81    public Extensions(
82        Extension[] extensions)
83    {
84        for (int i = 0; i != extensions.length; i++)
85        {
86            Extension ext = extensions[i];
87
88            this.ordering.addElement(ext.getExtnId());
89            this.extensions.put(ext.getExtnId(), ext);
90        }
91    }
92
93    /**
94     * return an Enumeration of the extension field's object ids.
95     */
96    public Enumeration oids()
97    {
98        return ordering.elements();
99    }
100
101    /**
102     * return the extension represented by the object identifier
103     * passed in.
104     *
105     * @return the extension if it's present, null otherwise.
106     */
107    public Extension getExtension(
108        ASN1ObjectIdentifier oid)
109    {
110        return (Extension)extensions.get(oid);
111    }
112
113    /**
114     * return the parsed value of the extension represented by the object identifier
115     * passed in.
116     *
117     * @return the parsed value of the extension if it's present, null otherwise.
118     */
119    public ASN1Encodable getExtensionParsedValue(ASN1ObjectIdentifier oid)
120    {
121        Extension ext = this.getExtension(oid);
122
123        if (ext != null)
124        {
125            return ext.getParsedValue();
126        }
127
128        return null;
129    }
130
131    /**
132     * <pre>
133     *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
134     *
135     *     Extension         ::=   SEQUENCE {
136     *        extnId            EXTENSION.&amp;id ({ExtensionSet}),
137     *        critical          BOOLEAN DEFAULT FALSE,
138     *        extnValue         OCTET STRING }
139     * </pre>
140     */
141    public ASN1Primitive toASN1Primitive()
142    {
143        ASN1EncodableVector vec = new ASN1EncodableVector();
144        Enumeration e = ordering.elements();
145
146        while (e.hasMoreElements())
147        {
148            ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement();
149            Extension ext = (Extension)extensions.get(oid);
150
151            vec.add(ext);
152        }
153
154        return new DERSequence(vec);
155    }
156
157    public boolean equivalent(
158        Extensions other)
159    {
160        if (extensions.size() != other.extensions.size())
161        {
162            return false;
163        }
164
165        Enumeration e1 = extensions.keys();
166
167        while (e1.hasMoreElements())
168        {
169            Object key = e1.nextElement();
170
171            if (!extensions.get(key).equals(other.extensions.get(key)))
172            {
173                return false;
174            }
175        }
176
177        return true;
178    }
179
180    public ASN1ObjectIdentifier[] getExtensionOIDs()
181    {
182        return toOidArray(ordering);
183    }
184
185    public ASN1ObjectIdentifier[] getNonCriticalExtensionOIDs()
186    {
187        return getExtensionOIDs(false);
188    }
189
190    public ASN1ObjectIdentifier[] getCriticalExtensionOIDs()
191    {
192        return getExtensionOIDs(true);
193    }
194
195    private ASN1ObjectIdentifier[] getExtensionOIDs(boolean isCritical)
196    {
197        Vector oidVec = new Vector();
198
199        for (int i = 0; i != ordering.size(); i++)
200        {
201            Object oid = ordering.elementAt(i);
202
203            if (((Extension)extensions.get(oid)).isCritical() == isCritical)
204            {
205                oidVec.addElement(oid);
206            }
207        }
208
209        return toOidArray(oidVec);
210    }
211
212    private ASN1ObjectIdentifier[] toOidArray(Vector oidVec)
213    {
214        ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[oidVec.size()];
215
216        for (int i = 0; i != oids.length; i++)
217        {
218            oids[i] = (ASN1ObjectIdentifier)oidVec.elementAt(i);
219        }
220        return oids;
221    }
222}
223