X500Name.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.asn1.x500;
2
3import java.util.Enumeration;
4
5import org.bouncycastle.asn1.ASN1Choice;
6import org.bouncycastle.asn1.ASN1Encodable;
7import org.bouncycastle.asn1.ASN1Object;
8import org.bouncycastle.asn1.ASN1ObjectIdentifier;
9import org.bouncycastle.asn1.ASN1Primitive;
10import org.bouncycastle.asn1.ASN1Sequence;
11import org.bouncycastle.asn1.ASN1TaggedObject;
12import org.bouncycastle.asn1.DERSequence;
13import org.bouncycastle.asn1.x500.style.BCStyle;
14
15/**
16 * <pre>
17 *     Name ::= CHOICE {
18 *                       RDNSequence }
19 *
20 *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
21 *
22 *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
23 *
24 *     AttributeTypeAndValue ::= SEQUENCE {
25 *                                   type  OBJECT IDENTIFIER,
26 *                                   value ANY }
27 * </pre>
28 */
29public class X500Name
30    extends ASN1Object
31    implements ASN1Choice
32{
33    private static X500NameStyle    defaultStyle = BCStyle.INSTANCE;
34
35    private boolean                 isHashCodeCalculated;
36    private int                     hashCodeValue;
37
38    private X500NameStyle style;
39    private RDN[] rdns;
40
41    public X500Name(X500NameStyle style, X500Name name)
42    {
43        this.rdns = name.rdns;
44        this.style = style;
45    }
46
47    /**
48     * Return a X500Name based on the passed in tagged object.
49     *
50     * @param obj tag object holding name.
51     * @param explicit true if explicitly tagged false otherwise.
52     * @return the X500Name
53     */
54    public static X500Name getInstance(
55        ASN1TaggedObject obj,
56        boolean          explicit)
57    {
58        // must be true as choice item
59        return getInstance(ASN1Sequence.getInstance(obj, true));
60    }
61
62    public static X500Name getInstance(
63        Object  obj)
64    {
65        if (obj instanceof X500Name)
66        {
67            return (X500Name)obj;
68        }
69        else if (obj != null)
70        {
71            return new X500Name(ASN1Sequence.getInstance(obj));
72        }
73
74        return null;
75    }
76
77    public static X500Name getInstance(
78        X500NameStyle style,
79        Object        obj)
80    {
81        if (obj instanceof X500Name)
82        {
83            return getInstance(style, ((X500Name)obj).toASN1Primitive());
84        }
85        else if (obj != null)
86        {
87            return new X500Name(style, ASN1Sequence.getInstance(obj));
88        }
89
90        return null;
91    }
92
93    /**
94     * Constructor from ASN1Sequence
95     *
96     * the principal will be a list of constructed sets, each containing an (OID, String) pair.
97     */
98    private X500Name(
99        ASN1Sequence  seq)
100    {
101        this(defaultStyle, seq);
102    }
103
104    private X500Name(
105        X500NameStyle style,
106        ASN1Sequence  seq)
107    {
108        this.style = style;
109        this.rdns = new RDN[seq.size()];
110
111        int index = 0;
112
113        for (Enumeration e = seq.getObjects(); e.hasMoreElements();)
114        {
115            rdns[index++] = RDN.getInstance(e.nextElement());
116        }
117    }
118
119    public X500Name(
120        RDN[] rDNs)
121    {
122        this(defaultStyle, rDNs);
123    }
124
125    public X500Name(
126        X500NameStyle style,
127        RDN[]         rDNs)
128    {
129        this.rdns = rDNs;
130        this.style = style;
131    }
132
133    public X500Name(
134        String dirName)
135    {
136        this(defaultStyle, dirName);
137    }
138
139    public X500Name(
140        X500NameStyle style,
141        String        dirName)
142    {
143        this(style.fromString(dirName));
144
145        this.style = style;
146    }
147
148    /**
149     * return an array of RDNs in structure order.
150     *
151     * @return an array of RDN objects.
152     */
153    public RDN[] getRDNs()
154    {
155        RDN[] tmp = new RDN[this.rdns.length];
156
157        System.arraycopy(rdns, 0, tmp, 0, tmp.length);
158
159        return tmp;
160    }
161
162    /**
163     * return an array of OIDs contained in the attribute type of each RDN in structure order.
164     *
165     * @return an array, possibly zero length, of ASN1ObjectIdentifiers objects.
166     */
167    public ASN1ObjectIdentifier[] getAttributeTypes()
168    {
169        int   count = 0;
170
171        for (int i = 0; i != rdns.length; i++)
172        {
173            RDN rdn = rdns[i];
174
175            count += rdn.size();
176        }
177
178        ASN1ObjectIdentifier[] res = new ASN1ObjectIdentifier[count];
179
180        count = 0;
181
182        for (int i = 0; i != rdns.length; i++)
183        {
184            RDN rdn = rdns[i];
185
186            if (rdn.isMultiValued())
187            {
188                AttributeTypeAndValue[] attr = rdn.getTypesAndValues();
189                for (int j = 0; j != attr.length; j++)
190                {
191                    res[count++] = attr[j].getType();
192                }
193            }
194            else if (rdn.size() != 0)
195            {
196                res[count++] = rdn.getFirst().getType();
197            }
198        }
199
200        return res;
201    }
202
203    /**
204     * return an array of RDNs containing the attribute type given by OID in structure order.
205     *
206     * @param attributeType the type OID we are looking for.
207     * @return an array, possibly zero length, of RDN objects.
208     */
209    public RDN[] getRDNs(ASN1ObjectIdentifier attributeType)
210    {
211        RDN[] res = new RDN[rdns.length];
212        int   count = 0;
213
214        for (int i = 0; i != rdns.length; i++)
215        {
216            RDN rdn = rdns[i];
217
218            if (rdn.isMultiValued())
219            {
220                AttributeTypeAndValue[] attr = rdn.getTypesAndValues();
221                for (int j = 0; j != attr.length; j++)
222                {
223                    if (attr[j].getType().equals(attributeType))
224                    {
225                        res[count++] = rdn;
226                        break;
227                    }
228                }
229            }
230            else
231            {
232                if (rdn.getFirst().getType().equals(attributeType))
233                {
234                    res[count++] = rdn;
235                }
236            }
237        }
238
239        RDN[] tmp = new RDN[count];
240
241        System.arraycopy(res, 0, tmp, 0, tmp.length);
242
243        return tmp;
244    }
245
246    public ASN1Primitive toASN1Primitive()
247    {
248        return new DERSequence(rdns);
249    }
250
251    public int hashCode()
252    {
253        if (isHashCodeCalculated)
254        {
255            return hashCodeValue;
256        }
257
258        isHashCodeCalculated = true;
259
260        hashCodeValue = style.calculateHashCode(this);
261
262        return hashCodeValue;
263    }
264
265    /**
266     * test for equality - note: case is ignored.
267     */
268    public boolean equals(Object obj)
269    {
270        if (obj == this)
271        {
272            return true;
273        }
274
275        if (!(obj instanceof X500Name || obj instanceof ASN1Sequence))
276        {
277            return false;
278        }
279
280        ASN1Primitive derO = ((ASN1Encodable)obj).toASN1Primitive();
281
282        if (this.toASN1Primitive().equals(derO))
283        {
284            return true;
285        }
286
287        try
288        {
289            return style.areEqual(this, new X500Name(ASN1Sequence.getInstance(((ASN1Encodable)obj).toASN1Primitive())));
290        }
291        catch (Exception e)
292        {
293            return false;
294        }
295    }
296
297    public String toString()
298    {
299        return style.toString(this);
300    }
301
302    /**
303     * Set the default style for X500Name construction.
304     *
305     * @param style  an X500NameStyle
306     */
307    public static void setDefaultStyle(X500NameStyle style)
308    {
309        if (style == null)
310        {
311            throw new NullPointerException("cannot set style to null");
312        }
313
314        defaultStyle = style;
315    }
316
317    /**
318     * Return the current default style.
319     *
320     * @return default style for X500Name construction.
321     */
322    public static X500NameStyle getDefaultStyle()
323    {
324        return defaultStyle;
325    }
326}
327