001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    
019    package org.apache.geronimo.util.asn1.x509;
020    
021    import java.util.Enumeration;
022    import java.util.Hashtable;
023    import java.util.Vector;
024    
025    import org.apache.geronimo.util.asn1.ASN1Encodable;
026    import org.apache.geronimo.util.asn1.ASN1EncodableVector;
027    import org.apache.geronimo.util.asn1.ASN1OctetString;
028    import org.apache.geronimo.util.asn1.ASN1Sequence;
029    import org.apache.geronimo.util.asn1.ASN1TaggedObject;
030    import org.apache.geronimo.util.asn1.DERBoolean;
031    import org.apache.geronimo.util.asn1.DERObject;
032    import org.apache.geronimo.util.asn1.DERObjectIdentifier;
033    import org.apache.geronimo.util.asn1.DERSequence;
034    
035    public class X509Extensions
036        extends ASN1Encodable
037    {
038        /**
039         * Subject Directory Attributes
040         */
041        public static final DERObjectIdentifier SubjectDirectoryAttributes = new DERObjectIdentifier("2.5.29.9");
042    
043        /**
044         * Subject Key Identifier
045         */
046        public static final DERObjectIdentifier SubjectKeyIdentifier = new DERObjectIdentifier("2.5.29.14");
047    
048        /**
049         * Key Usage
050         */
051        public static final DERObjectIdentifier KeyUsage = new DERObjectIdentifier("2.5.29.15");
052    
053        /**
054         * Private Key Usage Period
055         */
056        public static final DERObjectIdentifier PrivateKeyUsagePeriod = new DERObjectIdentifier("2.5.29.16");
057    
058        /**
059         * Subject Alternative Name
060         */
061        public static final DERObjectIdentifier SubjectAlternativeName = new DERObjectIdentifier("2.5.29.17");
062    
063        /**
064         * Issuer Alternative Name
065         */
066        public static final DERObjectIdentifier IssuerAlternativeName = new DERObjectIdentifier("2.5.29.18");
067    
068        /**
069         * Basic Constraints
070         */
071        public static final DERObjectIdentifier BasicConstraints = new DERObjectIdentifier("2.5.29.19");
072    
073        /**
074         * CRL Number
075         */
076        public static final DERObjectIdentifier CRLNumber = new DERObjectIdentifier("2.5.29.20");
077    
078        /**
079         * Reason code
080         */
081        public static final DERObjectIdentifier ReasonCode = new DERObjectIdentifier("2.5.29.21");
082    
083        /**
084         * Hold Instruction Code
085         */
086        public static final DERObjectIdentifier InstructionCode = new DERObjectIdentifier("2.5.29.23");
087    
088        /**
089         * Invalidity Date
090         */
091        public static final DERObjectIdentifier InvalidityDate = new DERObjectIdentifier("2.5.29.24");
092    
093        /**
094         * Delta CRL indicator
095         */
096        public static final DERObjectIdentifier DeltaCRLIndicator = new DERObjectIdentifier("2.5.29.27");
097    
098        /**
099         * Issuing Distribution Point
100         */
101        public static final DERObjectIdentifier IssuingDistributionPoint = new DERObjectIdentifier("2.5.29.28");
102    
103        /**
104         * Certificate Issuer
105         */
106        public static final DERObjectIdentifier CertificateIssuer = new DERObjectIdentifier("2.5.29.29");
107    
108        /**
109         * Name Constraints
110         */
111        public static final DERObjectIdentifier NameConstraints = new DERObjectIdentifier("2.5.29.30");
112    
113        /**
114         * CRL Distribution Points
115         */
116        public static final DERObjectIdentifier CRLDistributionPoints = new DERObjectIdentifier("2.5.29.31");
117    
118        /**
119         * Certificate Policies
120         */
121        public static final DERObjectIdentifier CertificatePolicies = new DERObjectIdentifier("2.5.29.32");
122    
123        /**
124         * Policy Mappings
125         */
126        public static final DERObjectIdentifier PolicyMappings = new DERObjectIdentifier("2.5.29.33");
127    
128        /**
129         * Authority Key Identifier
130         */
131        public static final DERObjectIdentifier AuthorityKeyIdentifier = new DERObjectIdentifier("2.5.29.35");
132    
133        /**
134         * Policy Constraints
135         */
136        public static final DERObjectIdentifier PolicyConstraints = new DERObjectIdentifier("2.5.29.36");
137    
138        /**
139         * Extended Key Usage
140         */
141        public static final DERObjectIdentifier ExtendedKeyUsage = new DERObjectIdentifier("2.5.29.37");
142    
143        /**
144         * Freshest CRL
145         */
146        public static final DERObjectIdentifier FreshestCRL = new DERObjectIdentifier("2.5.29.46");
147    
148        /**
149         * Inhibit Any Policy
150         */
151        public static final DERObjectIdentifier InhibitAnyPolicy = new DERObjectIdentifier("2.5.29.54");
152    
153        /**
154         * Authority Info Access
155         */
156        public static final DERObjectIdentifier AuthorityInfoAccess= new DERObjectIdentifier("1.3.6.1.5.5.7.1.1");
157    
158        /**
159         * Subject Info Access
160         */
161        public static final DERObjectIdentifier SubjectInfoAccess= new DERObjectIdentifier("1.3.6.1.5.5.7.1.11");
162    
163        private Hashtable               extensions = new Hashtable();
164        private Vector                  ordering = new Vector();
165    
166        public static X509Extensions getInstance(
167            ASN1TaggedObject obj,
168            boolean          explicit)
169        {
170            return getInstance(ASN1Sequence.getInstance(obj, explicit));
171        }
172    
173        public static X509Extensions getInstance(
174            Object  obj)
175        {
176            if (obj == null || obj instanceof X509Extensions)
177            {
178                return (X509Extensions)obj;
179            }
180    
181            if (obj instanceof ASN1Sequence)
182            {
183                return new X509Extensions((ASN1Sequence)obj);
184            }
185    
186            if (obj instanceof ASN1TaggedObject)
187            {
188                return getInstance(((ASN1TaggedObject)obj).getObject());
189            }
190    
191            throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
192        }
193    
194        /**
195         * Constructor from ASN1Sequence.
196         *
197         * the extensions are a list of constructed sequences, either with (OID, OctetString) or (OID, Boolean, OctetString)
198         */
199        public X509Extensions(
200            ASN1Sequence  seq)
201        {
202            Enumeration e = seq.getObjects();
203    
204            while (e.hasMoreElements())
205            {
206                ASN1Sequence            s = (ASN1Sequence)e.nextElement();
207    
208                if (s.size() == 3)
209                {
210                    extensions.put(s.getObjectAt(0), new X509Extension((DERBoolean)s.getObjectAt(1), (ASN1OctetString)s.getObjectAt(2)));
211                }
212                else
213                {
214                    extensions.put(s.getObjectAt(0), new X509Extension(false, (ASN1OctetString)s.getObjectAt(1)));
215                }
216    
217                ordering.addElement(s.getObjectAt(0));
218            }
219        }
220    
221        /**
222         * constructor from a table of extensions.
223         * <p>
224         * it's is assumed the table contains OID/String pairs.
225         */
226        public X509Extensions(
227            Hashtable  extensions)
228        {
229            this(null, extensions);
230        }
231    
232        /**
233         * Constructor from a table of extensions with ordering.
234         * <p>
235         * It's is assumed the table contains OID/String pairs.
236         */
237        public X509Extensions(
238            Vector      ordering,
239            Hashtable   extensions)
240        {
241            Enumeration e;
242    
243            if (ordering == null)
244            {
245                e = extensions.keys();
246            }
247            else
248            {
249                e = ordering.elements();
250            }
251    
252            while (e.hasMoreElements())
253            {
254                this.ordering.addElement(e.nextElement());
255            }
256    
257            e = this.ordering.elements();
258    
259            while (e.hasMoreElements())
260            {
261                DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
262                X509Extension           ext = (X509Extension)extensions.get(oid);
263    
264                this.extensions.put(oid, ext);
265            }
266        }
267    
268        /**
269         * Constructor from two vectors
270         *
271         * @param objectIDs a vector of the object identifiers.
272         * @param values a vector of the extension values.
273         */
274        public X509Extensions(
275            Vector      objectIDs,
276            Vector      values)
277        {
278            Enumeration e = objectIDs.elements();
279    
280            while (e.hasMoreElements())
281            {
282                this.ordering.addElement(e.nextElement());
283            }
284    
285            int count = 0;
286    
287            e = this.ordering.elements();
288    
289            while (e.hasMoreElements())
290            {
291                DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
292                X509Extension           ext = (X509Extension)values.elementAt(count);
293    
294                this.extensions.put(oid, ext);
295                count++;
296            }
297        }
298    
299        /**
300         * return an Enumeration of the extension field's object ids.
301         */
302        public Enumeration oids()
303        {
304            return ordering.elements();
305        }
306    
307        /**
308         * return the extension represented by the object identifier
309         * passed in.
310         *
311         * @return the extension if it's present, null otherwise.
312         */
313        public X509Extension getExtension(
314            DERObjectIdentifier oid)
315        {
316            return (X509Extension)extensions.get(oid);
317        }
318    
319        /**
320         * <pre>
321         *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
322         *
323         *     Extension         ::=   SEQUENCE {
324         *        extnId            EXTENSION.&id ({ExtensionSet}),
325         *        critical          BOOLEAN DEFAULT FALSE,
326         *        extnValue         OCTET STRING }
327         * </pre>
328         */
329        public DERObject toASN1Object()
330        {
331            ASN1EncodableVector     vec = new ASN1EncodableVector();
332            Enumeration             e = ordering.elements();
333    
334            while (e.hasMoreElements())
335            {
336                DERObjectIdentifier     oid = (DERObjectIdentifier)e.nextElement();
337                X509Extension           ext = (X509Extension)extensions.get(oid);
338                ASN1EncodableVector     v = new ASN1EncodableVector();
339    
340                v.add(oid);
341    
342                if (ext.isCritical())
343                {
344                    v.add(new DERBoolean(true));
345                }
346    
347                v.add(ext.getValue());
348    
349                vec.add(new DERSequence(v));
350            }
351    
352            return new DERSequence(vec);
353        }
354    
355        public int hashCode()
356        {
357            Enumeration     e = extensions.keys();
358            int             hashCode = 0;
359    
360            while (e.hasMoreElements())
361            {
362                Object  o = e.nextElement();
363    
364                hashCode ^= o.hashCode();
365                hashCode ^= extensions.get(o).hashCode();
366            }
367    
368            return hashCode;
369        }
370    
371        public boolean equals(
372            Object o)
373        {
374            if (o == null || !(o instanceof X509Extensions))
375            {
376                return false;
377            }
378    
379            X509Extensions  other = (X509Extensions)o;
380    
381            Enumeration     e1 = extensions.keys();
382            Enumeration     e2 = other.extensions.keys();
383    
384            while (e1.hasMoreElements() && e2.hasMoreElements())
385            {
386                Object  o1 = e1.nextElement();
387                Object  o2 = e2.nextElement();
388    
389                if (!o1.equals(o2))
390                {
391                    return false;
392                }
393            }
394    
395            if (e1.hasMoreElements() || e2.hasMoreElements())
396            {
397                return false;
398            }
399    
400            return true;
401        }
402    }