1    package org.bouncycastle.asn1.x509;
2    
3    import java.io.*;
4    import java.util.*;
5    
6    import org.bouncycastle.asn1.*;
7    
8    public class X509Extensions
9        implements DEREncodable
10   {
11       /**
12        * Subject Key Identifier 
13        */
14       public static final DERObjectIdentifier SubjectKeyIdentifier = new DERObjectIdentifier("2.5.29.14");
15   
16       /**
17        * Key Usage 
18        */
19       public static final DERObjectIdentifier KeyUsage = new DERObjectIdentifier("2.5.29.15");
20   
21       /**
22        * Private Key Usage Period 
23        */
24       public static final DERObjectIdentifier PrivateKeyUsagePeriod = new DERObjectIdentifier("2.5.29.16");
25   
26       /**
27        * Subject Alternative Name 
28        */
29       public static final DERObjectIdentifier SubjectAlternativeName = new DERObjectIdentifier("2.5.29.17");
30   
31       /**
32        * Issuer Alternative Name 
33        */
34       public static final DERObjectIdentifier IssuerAlternativeName = new DERObjectIdentifier("2.5.29.18");
35   
36       /**
37        * Basic Constraints 
38        */
39       public static final DERObjectIdentifier BasicConstraints = new DERObjectIdentifier("2.5.29.19");
40   
41       /**
42        * CRL Number 
43        */
44       public static final DERObjectIdentifier CRLNumber = new DERObjectIdentifier("2.5.29.20");
45   
46       /**
47        * Reason code 
48        */
49       public static final DERObjectIdentifier ReasonCode = new DERObjectIdentifier("2.5.29.21");
50   
51       /**
52        * Hold Instruction Code 
53        */
54       public static final DERObjectIdentifier InstructionCode = new DERObjectIdentifier("2.5.29.23");
55   
56       /**
57        * Invalidity Date 
58        */
59       public static final DERObjectIdentifier InvalidityDate = new DERObjectIdentifier("2.5.29.24");
60   
61       /**
62        * Delta CRL indicator 
63        */
64       public static final DERObjectIdentifier DeltaCRLIndicator = new DERObjectIdentifier("2.5.29.27");
65   
66       /**
67        * Issuing Distribution Point 
68        */
69       public static final DERObjectIdentifier IssuingDistributionPoint = new DERObjectIdentifier("2.5.29.28");
70   
71       /**
72        * Certificate Issuer 
73        */
74       public static final DERObjectIdentifier CertificateIssuer = new DERObjectIdentifier("2.5.29.29");
75   
76       /**
77        * Name Constraints 
78        */
79       public static final DERObjectIdentifier NameConstraints = new DERObjectIdentifier("2.5.29.30");
80   
81       /**
82        * CRL Distribution Points 
83        */
84       public static final DERObjectIdentifier CRLDistributionPoints = new DERObjectIdentifier("2.5.29.31");
85   
86       /**
87        * Certificate Policies 
88        */
89       public static final DERObjectIdentifier CertificatePolicies = new DERObjectIdentifier("2.5.29.32");
90   
91       /**
92        * Policy Mappings 
93        */
94       public static final DERObjectIdentifier PolicyMappings = new DERObjectIdentifier("2.5.29.33");
95   
96       /**
97        * Authority Key Identifier 
98        */
99       public static final DERObjectIdentifier AuthorityKeyIdentifier = new DERObjectIdentifier("2.5.29.35");
100  
101      /**
102       * Policy Constraints 
103       */
104      public static final DERObjectIdentifier PolicyConstraints = new DERObjectIdentifier("2.5.29.36");
105  
106      /**
107       * Extended Key Usage 
108       */
109      public static final DERObjectIdentifier ExtendedKeyUsage = new DERObjectIdentifier("2.5.29.37");
110  
111      private Hashtable               extensions = new Hashtable();
112      private Vector                  ordering = new Vector();
113  
114      public static X509Extensions getInstance(
115          ASN1TaggedObject obj,
116          boolean          explicit)
117      {
118          return getInstance(ASN1Sequence.getInstance(obj, explicit));
119      }
120  
121      public static X509Extensions getInstance(
122          Object  obj)
123      {
124          if (obj == null || obj instanceof X509Extensions)
125          {
126              return (X509Extensions)obj;
127          }
128  
129          if (obj instanceof ASN1Sequence)
130          {
131              return new X509Extensions((ASN1Sequence)obj);
132          }
133  
134          if (obj instanceof ASN1TaggedObject)
135          {
136              return getInstance(((ASN1TaggedObject)obj).getObject());
137          }
138  
139          throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
140      }
141  
142      /**
143       * Constructor from DERConstructedSequence.
144       *
145       * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString)
146       */
147      public X509Extensions(
148          ASN1Sequence  seq)
149      {
150          Enumeration e = seq.getObjects();
151  
152          while (e.hasMoreElements())
153          {
154              ASN1Sequence            s = (ASN1Sequence)e.nextElement();
155              Enumeration             e1 = s.getObjects();
156  
157              if (s.size() == 3)
158              {
159                  extensions.put(s.getObjectAt(0), new X509Extension((DERBoolean)s.getObjectAt(1), (DEROctetString)s.getObjectAt(2)));
160              }
161              else
162              {
163                  extensions.put(s.getObjectAt(0), new X509Extension(false, (DEROctetString)s.getObjectAt(1)));
164              }
165  
166              ordering.addElement(s.getObjectAt(0));
167          }
168      }
169  
170      /**
171       * constructor from a table of extensions.
172       * <p>
173       * it's is assumed the table contains OID/String pairs.
174       */
175      public X509Extensions(
176          Hashtable  extensions)
177      {
178          this(null, extensions);
179      }
180  
181      /**
182       * constructor from a table of extensions with ordering
183       * <p>
184       * it's is assumed the table contains OID/String pairs.
185       */
186      public X509Extensions(
187          Vector      ordering,
188          Hashtable   extensions)
189      {
190          Enumeration e;
191  
192          if (ordering == null)
193          {
194              e = extensions.keys();
195          }
196          else
197          {
198              e = ordering.elements();
199          }
200  
201          while (e.hasMoreElements())
202          {
203              this.ordering.addElement(e.nextElement()); 
204          }
205  
206          e = this.ordering.elements();
207  
208          while (e.hasMoreElements())
209          {
210              DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
211              X509Extension           ext = (X509Extension)extensions.get(oid);
212  
213              this.extensions.put(oid, ext);
214          }
215      }
216  
217      /**
218       * return an Enumeration of the extension field's object ids.
219       */
220      public Enumeration oids()
221      {
222          return ordering.elements();
223      }
224  
225      /**
226       * return the extension represented by the object identifier
227       * passed in.
228       *
229       * @return the extension if it's present, null otherwise.
230       */
231      public X509Extension getExtension(
232          DERObjectIdentifier oid)
233      {
234          return (X509Extension)extensions.get(oid);
235      }
236  
237      public DERObject getDERObject()
238      {
239          DEREncodableVector      vec = new DEREncodableVector();
240          Enumeration             e = ordering.elements();
241  
242          while (e.hasMoreElements())
243          {
244              DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
245              X509Extension           ext = (X509Extension)extensions.get(oid);
246              DEREncodableVector      v = new DEREncodableVector();
247  
248              v.add(oid);
249  
250              if (ext.isCritical())
251              {
252                  v.add(new DERBoolean(true));
253              }
254  
255              v.add(ext.getValue());
256  
257              vec.add(new DERSequence(v));
258          }
259  
260          return new DERSequence(vec);
261      }
262  
263      public int hashCode()
264      {
265          Enumeration     e = extensions.keys();
266          int             hashCode = 0;
267  
268          while (e.hasMoreElements())
269          {
270              Object  o = e.nextElement();
271  
272              hashCode ^= o.hashCode();
273              hashCode ^= extensions.get(o).hashCode();
274          }
275  
276          return hashCode;
277      }
278  
279      public boolean equals(
280          Object o)
281      {
282          if (o == null || !(o instanceof X509Extensions))
283          {
284              return false;
285          }
286  
287          X509Extensions  other = (X509Extensions)o;
288  
289          Enumeration     e1 = extensions.keys();
290          Enumeration     e2 = other.extensions.keys();
291  
292          while (e1.hasMoreElements() && e2.hasMoreElements())
293          {
294              Object  o1 = e1.nextElement();
295              Object  o2 = e2.nextElement();
296              
297              if (!o1.equals(o2))
298              {
299                  return false;
300              }
301          }
302  
303          if (e1.hasMoreElements() || e2.hasMoreElements())
304          {
305              return false;
306          }
307  
308          return true;
309      }
310  }
311