001package org.apache.commons.ssl.org.bouncycastle.asn1.x509;
002
003import java.util.Enumeration;
004import java.util.Hashtable;
005import java.util.Vector;
006
007import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Encodable;
008import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1EncodableVector;
009import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Object;
010import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1ObjectIdentifier;
011import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Primitive;
012import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1Sequence;
013import org.apache.commons.ssl.org.bouncycastle.asn1.ASN1TaggedObject;
014import org.apache.commons.ssl.org.bouncycastle.asn1.DERSequence;
015
016/**
017 * The extendedKeyUsage object.
018 * <pre>
019 *      extendedKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
020 * </pre>
021 */
022public class ExtendedKeyUsage
023    extends ASN1Object
024{
025    Hashtable     usageTable = new Hashtable();
026    ASN1Sequence  seq;
027
028    /**
029     * Return an ExtendedKeyUsage from the passed in tagged object.
030     *
031     * @param obj the tagged object containing the ExtendedKeyUsage
032     * @param explicit true if the tagged object should be interpreted as explicitly tagged, false if implicit.
033     * @return the ExtendedKeyUsage contained.
034     */
035    public static ExtendedKeyUsage getInstance(
036        ASN1TaggedObject obj,
037        boolean          explicit)
038    {
039        return getInstance(ASN1Sequence.getInstance(obj, explicit));
040    }
041
042    /**
043     * Return an ExtendedKeyUsage from the passed in object.
044     *
045     * @param obj an ExtendedKeyUsage, some form or encoding of one, or null.
046     * @return  an ExtendedKeyUsage object, or null if null is passed in.
047     */
048    public static ExtendedKeyUsage getInstance(
049        Object obj)
050    {
051        if (obj instanceof ExtendedKeyUsage) 
052        {
053            return (ExtendedKeyUsage)obj;
054        }
055        else if (obj != null)
056        {
057            return new ExtendedKeyUsage(ASN1Sequence.getInstance(obj));
058        }
059
060        return null;
061    }
062
063    /**
064     * Retrieve an ExtendedKeyUsage for a passed in Extensions object, if present.
065     *
066     * @param extensions the extensions object to be examined.
067     * @return  the ExtendedKeyUsage, null if the extension is not present.
068     */
069    public static ExtendedKeyUsage fromExtensions(Extensions extensions)
070    {
071        return ExtendedKeyUsage.getInstance(extensions.getExtensionParsedValue(Extension.extendedKeyUsage));
072    }
073
074    /**
075     * Base constructor, from a single KeyPurposeId.
076     *
077     * @param usage the keyPurposeId to be included.
078     */
079    public ExtendedKeyUsage(
080        KeyPurposeId  usage)
081    {
082        this.seq = new DERSequence(usage);
083
084        this.usageTable.put(usage, usage);
085    }
086    
087    private ExtendedKeyUsage(
088        ASN1Sequence  seq)
089    {
090        this.seq = seq;
091
092        Enumeration e = seq.getObjects();
093
094        while (e.hasMoreElements())
095        {
096            ASN1Encodable o = (ASN1Encodable)e.nextElement();
097            if (!(o.toASN1Primitive() instanceof ASN1ObjectIdentifier))
098            {
099                throw new IllegalArgumentException("Only ASN1ObjectIdentifiers allowed in ExtendedKeyUsage.");
100            }
101            this.usageTable.put(o, o);
102        }
103    }
104
105    /**
106     * Base constructor, from multiple KeyPurposeIds.
107     *
108     * @param usages an array of KeyPurposeIds.
109     */
110    public ExtendedKeyUsage(
111        KeyPurposeId[]  usages)
112    {
113        ASN1EncodableVector v = new ASN1EncodableVector();
114
115        for (int i = 0; i != usages.length; i++)
116        {
117            v.add(usages[i]);
118            this.usageTable.put(usages[i], usages[i]);
119        }
120
121        this.seq = new DERSequence(v);
122    }
123
124    /**
125     * @deprecated use KeyPurposeId[] constructor.
126     */
127    public ExtendedKeyUsage(
128        Vector usages)
129    {
130        ASN1EncodableVector v = new ASN1EncodableVector();
131        Enumeration         e = usages.elements();
132
133        while (e.hasMoreElements())
134        {
135            KeyPurposeId  o = KeyPurposeId.getInstance(e.nextElement());
136
137            v.add(o);
138            this.usageTable.put(o, o);
139        }
140
141        this.seq = new DERSequence(v);
142    }
143
144    /**
145     * Return true if this ExtendedKeyUsage object contains the passed in keyPurposeId.
146     *
147     * @param keyPurposeId  the KeyPurposeId of interest.
148     * @return true if the keyPurposeId is present, false otherwise.
149     */
150    public boolean hasKeyPurposeId(
151        KeyPurposeId keyPurposeId)
152    {
153        return (usageTable.get(keyPurposeId) != null);
154    }
155    
156    /**
157     * Returns all extended key usages.
158     *
159     * @return An array with all key purposes.
160     */
161    public KeyPurposeId[] getUsages()
162    {
163        KeyPurposeId[] temp = new KeyPurposeId[seq.size()];
164
165        int i = 0;
166        for (Enumeration it = seq.getObjects(); it.hasMoreElements();)
167        {
168            temp[i++] = KeyPurposeId.getInstance(it.nextElement());
169        }
170        return temp;
171    }
172
173    /**
174     * Return the number of KeyPurposeIds present in this ExtendedKeyUsage.
175     *
176     * @return the number of KeyPurposeIds
177     */
178    public int size()
179    {
180        return usageTable.size();
181    }
182
183    /**
184     * Return the ASN.1 primitive form of this object.
185     *
186     * @return an ASN1Sequence.
187     */
188    public ASN1Primitive toASN1Primitive()
189    {
190        return seq;
191    }
192}