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