1package org.bouncycastle.asn1.x509;
2
3import java.io.IOException;
4import java.util.Enumeration;
5import java.util.Hashtable;
6import java.util.Vector;
7
8import org.bouncycastle.asn1.ASN1Encodable;
9import org.bouncycastle.asn1.ASN1EncodableVector;
10import org.bouncycastle.asn1.ASN1Object;
11import org.bouncycastle.asn1.ASN1Sequence;
12import org.bouncycastle.asn1.ASN1Set;
13import org.bouncycastle.asn1.ASN1TaggedObject;
14import org.bouncycastle.asn1.DEREncodable;
15import org.bouncycastle.asn1.DERObject;
16import org.bouncycastle.asn1.DERObjectIdentifier;
17import org.bouncycastle.asn1.DERSequence;
18import org.bouncycastle.asn1.DERSet;
19import org.bouncycastle.asn1.DERString;
20import org.bouncycastle.asn1.DERUniversalString;
21import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
22import org.bouncycastle.asn1.x500.X500Name;
23import org.bouncycastle.util.Strings;
24import org.bouncycastle.util.encoders.Hex;
25
26/**
27 * <pre>
28 *     RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
29 *
30 *     RelativeDistinguishedName ::= SET SIZE (1..MAX) OF AttributeTypeAndValue
31 *
32 *     AttributeTypeAndValue ::= SEQUENCE {
33 *                                   type  OBJECT IDENTIFIER,
34 *                                   value ANY }
35 * </pre>
36 * @deprecated use org.bouncycastle.asn1.x500.X500Name.
37 */
38public class X509Name
39    extends ASN1Encodable
40{
41    /**
42     * country code - StringType(SIZE(2))
43     */
44    public static final DERObjectIdentifier C = new DERObjectIdentifier("2.5.4.6");
45
46    /**
47     * organization - StringType(SIZE(1..64))
48     */
49    public static final DERObjectIdentifier O = new DERObjectIdentifier("2.5.4.10");
50
51    /**
52     * organizational unit name - StringType(SIZE(1..64))
53     */
54    public static final DERObjectIdentifier OU = new DERObjectIdentifier("2.5.4.11");
55
56    /**
57     * Title
58     */
59    public static final DERObjectIdentifier T = new DERObjectIdentifier("2.5.4.12");
60
61    /**
62     * common name - StringType(SIZE(1..64))
63     */
64    public static final DERObjectIdentifier CN = new DERObjectIdentifier("2.5.4.3");
65
66    /**
67     * device serial number name - StringType(SIZE(1..64))
68     */
69    public static final DERObjectIdentifier SN = new DERObjectIdentifier("2.5.4.5");
70
71    /**
72     * street - StringType(SIZE(1..64))
73     */
74    public static final DERObjectIdentifier STREET = new DERObjectIdentifier("2.5.4.9");
75
76    /**
77     * device serial number name - StringType(SIZE(1..64))
78     */
79    public static final DERObjectIdentifier SERIALNUMBER = SN;
80
81    /**
82     * locality name - StringType(SIZE(1..64))
83     */
84    public static final DERObjectIdentifier L = new DERObjectIdentifier("2.5.4.7");
85
86    /**
87     * state, or province name - StringType(SIZE(1..64))
88     */
89    public static final DERObjectIdentifier ST = new DERObjectIdentifier("2.5.4.8");
90
91    /**
92     * Naming attributes of type X520name
93     */
94    public static final DERObjectIdentifier SURNAME = new DERObjectIdentifier("2.5.4.4");
95    public static final DERObjectIdentifier GIVENNAME = new DERObjectIdentifier("2.5.4.42");
96    public static final DERObjectIdentifier INITIALS = new DERObjectIdentifier("2.5.4.43");
97    public static final DERObjectIdentifier GENERATION = new DERObjectIdentifier("2.5.4.44");
98    public static final DERObjectIdentifier UNIQUE_IDENTIFIER = new DERObjectIdentifier("2.5.4.45");
99
100    /**
101     * businessCategory - DirectoryString(SIZE(1..128)
102     */
103    public static final DERObjectIdentifier BUSINESS_CATEGORY = new DERObjectIdentifier(
104                    "2.5.4.15");
105
106    /**
107     * postalCode - DirectoryString(SIZE(1..40)
108     */
109    public static final DERObjectIdentifier POSTAL_CODE = new DERObjectIdentifier(
110                    "2.5.4.17");
111
112    /**
113     * dnQualifier - DirectoryString(SIZE(1..64)
114     */
115    public static final DERObjectIdentifier DN_QUALIFIER = new DERObjectIdentifier(
116                    "2.5.4.46");
117
118    /**
119     * RFC 3039 Pseudonym - DirectoryString(SIZE(1..64)
120     */
121    public static final DERObjectIdentifier PSEUDONYM = new DERObjectIdentifier(
122                    "2.5.4.65");
123
124
125    /**
126     * RFC 3039 DateOfBirth - GeneralizedTime - YYYYMMDD000000Z
127     */
128    public static final DERObjectIdentifier DATE_OF_BIRTH = new DERObjectIdentifier(
129                    "1.3.6.1.5.5.7.9.1");
130
131    /**
132     * RFC 3039 PlaceOfBirth - DirectoryString(SIZE(1..128)
133     */
134    public static final DERObjectIdentifier PLACE_OF_BIRTH = new DERObjectIdentifier(
135                    "1.3.6.1.5.5.7.9.2");
136
137    /**
138     * RFC 3039 Gender - PrintableString (SIZE(1)) -- "M", "F", "m" or "f"
139     */
140    public static final DERObjectIdentifier GENDER = new DERObjectIdentifier(
141                    "1.3.6.1.5.5.7.9.3");
142
143    /**
144     * RFC 3039 CountryOfCitizenship - PrintableString (SIZE (2)) -- ISO 3166
145     * codes only
146     */
147    public static final DERObjectIdentifier COUNTRY_OF_CITIZENSHIP = new DERObjectIdentifier(
148                    "1.3.6.1.5.5.7.9.4");
149
150    /**
151     * RFC 3039 CountryOfResidence - PrintableString (SIZE (2)) -- ISO 3166
152     * codes only
153     */
154    public static final DERObjectIdentifier COUNTRY_OF_RESIDENCE = new DERObjectIdentifier(
155                    "1.3.6.1.5.5.7.9.5");
156
157
158    /**
159     * ISIS-MTT NameAtBirth - DirectoryString(SIZE(1..64)
160     */
161    public static final DERObjectIdentifier NAME_AT_BIRTH =  new DERObjectIdentifier("1.3.36.8.3.14");
162
163    /**
164     * RFC 3039 PostalAddress - SEQUENCE SIZE (1..6) OF
165     * DirectoryString(SIZE(1..30))
166     */
167    public static final DERObjectIdentifier POSTAL_ADDRESS = new DERObjectIdentifier("2.5.4.16");
168
169    /**
170     * RFC 2256 dmdName
171     */
172    public static final DERObjectIdentifier DMD_NAME = new DERObjectIdentifier("2.5.4.54");
173
174    /**
175     * id-at-telephoneNumber
176     */
177    public static final DERObjectIdentifier TELEPHONE_NUMBER = X509ObjectIdentifiers.id_at_telephoneNumber;
178
179    /**
180     * id-at-name
181     */
182    public static final DERObjectIdentifier NAME = X509ObjectIdentifiers.id_at_name;
183
184    /**
185     * Email address (RSA PKCS#9 extension) - IA5String.
186     * <p>Note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
187     */
188    public static final DERObjectIdentifier EmailAddress = PKCSObjectIdentifiers.pkcs_9_at_emailAddress;
189
190    /**
191     * more from PKCS#9
192     */
193    public static final DERObjectIdentifier UnstructuredName = PKCSObjectIdentifiers.pkcs_9_at_unstructuredName;
194    public static final DERObjectIdentifier UnstructuredAddress = PKCSObjectIdentifiers.pkcs_9_at_unstructuredAddress;
195
196    /**
197     * email address in Verisign certificates
198     */
199    public static final DERObjectIdentifier E = EmailAddress;
200
201    /*
202     * others...
203     */
204    public static final DERObjectIdentifier DC = new DERObjectIdentifier("0.9.2342.19200300.100.1.25");
205
206    /**
207     * LDAP User id.
208     */
209    public static final DERObjectIdentifier UID = new DERObjectIdentifier("0.9.2342.19200300.100.1.1");
210
211    /**
212     * determines whether or not strings should be processed and printed
213     * from back to front.
214     */
215    public static boolean DefaultReverse = false;
216
217    /**
218     * default look up table translating OID values into their common symbols following
219     * the convention in RFC 2253 with a few extras
220     */
221    public static final Hashtable DefaultSymbols = new Hashtable();
222
223    /**
224     * look up table translating OID values into their common symbols following the convention in RFC 2253
225     *
226     */
227    public static final Hashtable RFC2253Symbols = new Hashtable();
228
229    /**
230     * look up table translating OID values into their common symbols following the convention in RFC 1779
231     *
232     */
233    public static final Hashtable RFC1779Symbols = new Hashtable();
234
235    /**
236     * look up table translating common symbols into their OIDS.
237     */
238    public static final Hashtable DefaultLookUp = new Hashtable();
239
240    /**
241     * look up table translating OID values into their common symbols
242     * @deprecated use DefaultSymbols
243     */
244    public static final Hashtable OIDLookUp = DefaultSymbols;
245
246    /**
247     * look up table translating string values into their OIDS -
248     * @deprecated use DefaultLookUp
249     */
250    public static final Hashtable SymbolLookUp = DefaultLookUp;
251
252    // BEGIN android-changed
253    private static final Boolean TRUE = Boolean.TRUE;
254    private static final Boolean FALSE = Boolean.FALSE;
255    // END android-changed
256
257    static
258    {
259        DefaultSymbols.put(C, "C");
260        DefaultSymbols.put(O, "O");
261        DefaultSymbols.put(T, "T");
262        DefaultSymbols.put(OU, "OU");
263        DefaultSymbols.put(CN, "CN");
264        DefaultSymbols.put(L, "L");
265        DefaultSymbols.put(ST, "ST");
266        DefaultSymbols.put(SN, "SERIALNUMBER");
267        DefaultSymbols.put(EmailAddress, "E");
268        DefaultSymbols.put(DC, "DC");
269        DefaultSymbols.put(UID, "UID");
270        DefaultSymbols.put(STREET, "STREET");
271        DefaultSymbols.put(SURNAME, "SURNAME");
272        DefaultSymbols.put(GIVENNAME, "GIVENNAME");
273        DefaultSymbols.put(INITIALS, "INITIALS");
274        DefaultSymbols.put(GENERATION, "GENERATION");
275        DefaultSymbols.put(UnstructuredAddress, "unstructuredAddress");
276        DefaultSymbols.put(UnstructuredName, "unstructuredName");
277        DefaultSymbols.put(UNIQUE_IDENTIFIER, "UniqueIdentifier");
278        DefaultSymbols.put(DN_QUALIFIER, "DN");
279        DefaultSymbols.put(PSEUDONYM, "Pseudonym");
280        DefaultSymbols.put(POSTAL_ADDRESS, "PostalAddress");
281        DefaultSymbols.put(NAME_AT_BIRTH, "NameAtBirth");
282        DefaultSymbols.put(COUNTRY_OF_CITIZENSHIP, "CountryOfCitizenship");
283        DefaultSymbols.put(COUNTRY_OF_RESIDENCE, "CountryOfResidence");
284        DefaultSymbols.put(GENDER, "Gender");
285        DefaultSymbols.put(PLACE_OF_BIRTH, "PlaceOfBirth");
286        DefaultSymbols.put(DATE_OF_BIRTH, "DateOfBirth");
287        DefaultSymbols.put(POSTAL_CODE, "PostalCode");
288        DefaultSymbols.put(BUSINESS_CATEGORY, "BusinessCategory");
289        DefaultSymbols.put(TELEPHONE_NUMBER, "TelephoneNumber");
290        DefaultSymbols.put(NAME, "Name");
291
292        RFC2253Symbols.put(C, "C");
293        RFC2253Symbols.put(O, "O");
294        RFC2253Symbols.put(OU, "OU");
295        RFC2253Symbols.put(CN, "CN");
296        RFC2253Symbols.put(L, "L");
297        RFC2253Symbols.put(ST, "ST");
298        RFC2253Symbols.put(STREET, "STREET");
299        RFC2253Symbols.put(DC, "DC");
300        RFC2253Symbols.put(UID, "UID");
301
302        RFC1779Symbols.put(C, "C");
303        RFC1779Symbols.put(O, "O");
304        RFC1779Symbols.put(OU, "OU");
305        RFC1779Symbols.put(CN, "CN");
306        RFC1779Symbols.put(L, "L");
307        RFC1779Symbols.put(ST, "ST");
308        RFC1779Symbols.put(STREET, "STREET");
309
310        DefaultLookUp.put("c", C);
311        DefaultLookUp.put("o", O);
312        DefaultLookUp.put("t", T);
313        DefaultLookUp.put("ou", OU);
314        DefaultLookUp.put("cn", CN);
315        DefaultLookUp.put("l", L);
316        DefaultLookUp.put("st", ST);
317        DefaultLookUp.put("sn", SN);
318        DefaultLookUp.put("serialnumber", SN);
319        DefaultLookUp.put("street", STREET);
320        DefaultLookUp.put("emailaddress", E);
321        DefaultLookUp.put("dc", DC);
322        DefaultLookUp.put("e", E);
323        DefaultLookUp.put("uid", UID);
324        DefaultLookUp.put("surname", SURNAME);
325        DefaultLookUp.put("givenname", GIVENNAME);
326        DefaultLookUp.put("initials", INITIALS);
327        DefaultLookUp.put("generation", GENERATION);
328        DefaultLookUp.put("unstructuredaddress", UnstructuredAddress);
329        DefaultLookUp.put("unstructuredname", UnstructuredName);
330        DefaultLookUp.put("uniqueidentifier", UNIQUE_IDENTIFIER);
331        DefaultLookUp.put("dn", DN_QUALIFIER);
332        DefaultLookUp.put("pseudonym", PSEUDONYM);
333        DefaultLookUp.put("postaladdress", POSTAL_ADDRESS);
334        DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH);
335        DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP);
336        DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE);
337        DefaultLookUp.put("gender", GENDER);
338        DefaultLookUp.put("placeofbirth", PLACE_OF_BIRTH);
339        DefaultLookUp.put("dateofbirth", DATE_OF_BIRTH);
340        DefaultLookUp.put("postalcode", POSTAL_CODE);
341        DefaultLookUp.put("businesscategory", BUSINESS_CATEGORY);
342        DefaultLookUp.put("telephonenumber", TELEPHONE_NUMBER);
343        DefaultLookUp.put("name", NAME);
344    }
345
346    private X509NameEntryConverter  converter = null;
347    private Vector                  ordering = new Vector();
348    private Vector                  values = new Vector();
349    private Vector                  added = new Vector();
350
351    private ASN1Sequence            seq;
352
353    private boolean                 isHashCodeCalculated;
354    private int                     hashCodeValue;
355
356    /**
357     * Return a X509Name based on the passed in tagged object.
358     *
359     * @param obj tag object holding name.
360     * @param explicit true if explicitly tagged false otherwise.
361     * @return the X509Name
362     */
363    public static X509Name getInstance(
364        ASN1TaggedObject obj,
365        boolean          explicit)
366    {
367        return getInstance(ASN1Sequence.getInstance(obj, explicit));
368    }
369
370    public static X509Name getInstance(
371        Object  obj)
372    {
373        if (obj == null || obj instanceof X509Name)
374        {
375            return (X509Name)obj;
376        }
377        else if (obj instanceof X500Name)
378        {
379            return new X509Name(ASN1Sequence.getInstance(((X500Name)obj).getDERObject()));
380        }
381        else if (obj != null)
382        {
383            return new X509Name(ASN1Sequence.getInstance(obj));
384        }
385
386        return null;
387    }
388
389    protected X509Name()
390    {
391        // constructure use by new X500 Name class
392    }
393    /**
394     * Constructor from ASN1Sequence
395     *
396     * the principal will be a list of constructed sets, each containing an (OID, String) pair.
397     */
398    public X509Name(
399        ASN1Sequence  seq)
400    {
401        this.seq = seq;
402
403        Enumeration e = seq.getObjects();
404
405        while (e.hasMoreElements())
406        {
407            ASN1Set         set = ASN1Set.getInstance(((DEREncodable)e.nextElement()).getDERObject());
408
409            for (int i = 0; i < set.size(); i++)
410            {
411                   ASN1Sequence s = ASN1Sequence.getInstance(set.getObjectAt(i));
412
413                   if (s.size() != 2)
414                   {
415                       throw new IllegalArgumentException("badly sized pair");
416                   }
417
418                   ordering.addElement(DERObjectIdentifier.getInstance(s.getObjectAt(0)));
419
420                   DEREncodable value = s.getObjectAt(1);
421                   if (value instanceof DERString && !(value instanceof DERUniversalString))
422                   {
423                       String v = ((DERString)value).getString();
424                       if (v.length() > 0 && v.charAt(0) == '#')
425                       {
426                           values.addElement("\\" + v);
427                       }
428                       else
429                       {
430                           values.addElement(v);
431                       }
432                   }
433                   else
434                   {
435                       values.addElement("#" + bytesToString(Hex.encode(value.getDERObject().getDEREncoded())));
436                   }
437                   // BEGIN android-changed
438                   added.addElement(Boolean.valueOf(i != 0));
439                   // END android-changed
440            }
441        }
442    }
443
444    /**
445     * constructor from a table of attributes.
446     * <p>
447     * it's is assumed the table contains OID/String pairs, and the contents
448     * of the table are copied into an internal table as part of the
449     * construction process.
450     * <p>
451     * <b>Note:</b> if the name you are trying to generate should be
452     * following a specific ordering, you should use the constructor
453     * with the ordering specified below.
454     * @deprecated use an ordered constructor! The hashtable ordering is rarely correct
455     */
456    public X509Name(
457        Hashtable  attributes)
458    {
459        this(null, attributes);
460    }
461
462    /**
463     * Constructor from a table of attributes with ordering.
464     * <p>
465     * it's is assumed the table contains OID/String pairs, and the contents
466     * of the table are copied into an internal table as part of the
467     * construction process. The ordering vector should contain the OIDs
468     * in the order they are meant to be encoded or printed in toString.
469     */
470    public X509Name(
471        Vector      ordering,
472        Hashtable   attributes)
473    {
474        this(ordering, attributes, new X509DefaultEntryConverter());
475    }
476
477    /**
478     * Constructor from a table of attributes with ordering.
479     * <p>
480     * it's is assumed the table contains OID/String pairs, and the contents
481     * of the table are copied into an internal table as part of the
482     * construction process. The ordering vector should contain the OIDs
483     * in the order they are meant to be encoded or printed in toString.
484     * <p>
485     * The passed in converter will be used to convert the strings into their
486     * ASN.1 counterparts.
487     */
488    public X509Name(
489        Vector                   ordering,
490        Hashtable                attributes,
491        X509NameEntryConverter   converter)
492    {
493        this.converter = converter;
494
495        if (ordering != null)
496        {
497            for (int i = 0; i != ordering.size(); i++)
498            {
499                this.ordering.addElement(ordering.elementAt(i));
500                this.added.addElement(FALSE);
501            }
502        }
503        else
504        {
505            Enumeration     e = attributes.keys();
506
507            while (e.hasMoreElements())
508            {
509                this.ordering.addElement(e.nextElement());
510                this.added.addElement(FALSE);
511            }
512        }
513
514        for (int i = 0; i != this.ordering.size(); i++)
515        {
516            DERObjectIdentifier     oid = (DERObjectIdentifier)this.ordering.elementAt(i);
517
518            if (attributes.get(oid) == null)
519            {
520                throw new IllegalArgumentException("No attribute for object id - " + oid.getId() + " - passed to distinguished name");
521            }
522
523            this.values.addElement(attributes.get(oid)); // copy the hash table
524        }
525    }
526
527    /**
528     * Takes two vectors one of the oids and the other of the values.
529     */
530    public X509Name(
531        Vector  oids,
532        Vector  values)
533    {
534        this(oids, values, new X509DefaultEntryConverter());
535    }
536
537    /**
538     * Takes two vectors one of the oids and the other of the values.
539     * <p>
540     * The passed in converter will be used to convert the strings into their
541     * ASN.1 counterparts.
542     */
543    public X509Name(
544        Vector                  oids,
545        Vector                  values,
546        X509NameEntryConverter  converter)
547    {
548        this.converter = converter;
549
550        if (oids.size() != values.size())
551        {
552            throw new IllegalArgumentException("oids vector must be same length as values.");
553        }
554
555        for (int i = 0; i < oids.size(); i++)
556        {
557            this.ordering.addElement(oids.elementAt(i));
558            this.values.addElement(values.elementAt(i));
559            this.added.addElement(FALSE);
560        }
561    }
562
563//    private Boolean isEncoded(String s)
564//    {
565//        if (s.charAt(0) == '#')
566//        {
567//            return TRUE;
568//        }
569//
570//        return FALSE;
571//    }
572
573    /**
574     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
575     * some such, converting it into an ordered set of name attributes.
576     */
577    public X509Name(
578        String  dirName)
579    {
580        this(DefaultReverse, DefaultLookUp, dirName);
581    }
582
583    /**
584     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
585     * some such, converting it into an ordered set of name attributes with each
586     * string value being converted to its associated ASN.1 type using the passed
587     * in converter.
588     */
589    public X509Name(
590        String                  dirName,
591        X509NameEntryConverter  converter)
592    {
593        this(DefaultReverse, DefaultLookUp, dirName, converter);
594    }
595
596    /**
597     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
598     * some such, converting it into an ordered set of name attributes. If reverse
599     * is true, create the encoded version of the sequence starting from the
600     * last element in the string.
601     */
602    public X509Name(
603        boolean reverse,
604        String  dirName)
605    {
606        this(reverse, DefaultLookUp, dirName);
607    }
608
609    /**
610     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
611     * some such, converting it into an ordered set of name attributes with each
612     * string value being converted to its associated ASN.1 type using the passed
613     * in converter. If reverse is true the ASN.1 sequence representing the DN will
614     * be built by starting at the end of the string, rather than the start.
615     */
616    public X509Name(
617        boolean                 reverse,
618        String                  dirName,
619        X509NameEntryConverter  converter)
620    {
621        this(reverse, DefaultLookUp, dirName, converter);
622    }
623
624    /**
625     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
626     * some such, converting it into an ordered set of name attributes. lookUp
627     * should provide a table of lookups, indexed by lowercase only strings and
628     * yielding a DERObjectIdentifier, other than that OID. and numeric oids
629     * will be processed automatically.
630     * <br>
631     * If reverse is true, create the encoded version of the sequence
632     * starting from the last element in the string.
633     * @param reverse true if we should start scanning from the end (RFC 2553).
634     * @param lookUp table of names and their oids.
635     * @param dirName the X.500 string to be parsed.
636     */
637    public X509Name(
638        boolean     reverse,
639        Hashtable   lookUp,
640        String      dirName)
641    {
642        this(reverse, lookUp, dirName, new X509DefaultEntryConverter());
643    }
644
645    private DERObjectIdentifier decodeOID(
646        String      name,
647        Hashtable   lookUp)
648    {
649        if (Strings.toUpperCase(name).startsWith("OID."))
650        {
651            return new DERObjectIdentifier(name.substring(4));
652        }
653        else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')
654        {
655            return new DERObjectIdentifier(name);
656        }
657
658        DERObjectIdentifier oid = (DERObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
659        if (oid == null)
660        {
661            throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
662        }
663
664        return oid;
665    }
666
667    /**
668     * Takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
669     * some such, converting it into an ordered set of name attributes. lookUp
670     * should provide a table of lookups, indexed by lowercase only strings and
671     * yielding a DERObjectIdentifier, other than that OID. and numeric oids
672     * will be processed automatically. The passed in converter is used to convert the
673     * string values to the right of each equals sign to their ASN.1 counterparts.
674     * <br>
675     * @param reverse true if we should start scanning from the end, false otherwise.
676     * @param lookUp table of names and oids.
677     * @param dirName the string dirName
678     * @param converter the converter to convert string values into their ASN.1 equivalents
679     */
680    public X509Name(
681        boolean                 reverse,
682        Hashtable               lookUp,
683        String                  dirName,
684        X509NameEntryConverter  converter)
685    {
686        this.converter = converter;
687        X509NameTokenizer   nTok = new X509NameTokenizer(dirName);
688
689        while (nTok.hasMoreTokens())
690        {
691            String  token = nTok.nextToken();
692            int     index = token.indexOf('=');
693
694            if (index == -1)
695            {
696                // BEGIN android-changed
697                throw new IllegalArgumentException("badly formatted directory string");
698                // END android-changed
699            }
700
701            String              name = token.substring(0, index);
702            String              value = token.substring(index + 1);
703            DERObjectIdentifier oid = decodeOID(name, lookUp);
704
705            if (value.indexOf('+') > 0)
706            {
707                X509NameTokenizer   vTok = new X509NameTokenizer(value, '+');
708                String  v = vTok.nextToken();
709
710                this.ordering.addElement(oid);
711                this.values.addElement(v);
712                this.added.addElement(FALSE);
713
714                while (vTok.hasMoreTokens())
715                {
716                    String  sv = vTok.nextToken();
717                    int     ndx = sv.indexOf('=');
718
719                    String  nm = sv.substring(0, ndx);
720                    String  vl = sv.substring(ndx + 1);
721                    this.ordering.addElement(decodeOID(nm, lookUp));
722                    this.values.addElement(vl);
723                    this.added.addElement(TRUE);
724                }
725            }
726            else
727            {
728                this.ordering.addElement(oid);
729                this.values.addElement(value);
730                this.added.addElement(FALSE);
731            }
732        }
733
734        if (reverse)
735        {
736            Vector  o = new Vector();
737            Vector  v = new Vector();
738            Vector  a = new Vector();
739
740            int count = 1;
741
742            for (int i = 0; i < this.ordering.size(); i++)
743            {
744                if (((Boolean)this.added.elementAt(i)).booleanValue())
745                {
746                    o.insertElementAt(this.ordering.elementAt(i), count);
747                    v.insertElementAt(this.values.elementAt(i), count);
748                    a.insertElementAt(this.added.elementAt(i), count);
749                    count++;
750                }
751                else
752                {
753                    o.insertElementAt(this.ordering.elementAt(i), 0);
754                    v.insertElementAt(this.values.elementAt(i), 0);
755                    a.insertElementAt(this.added.elementAt(i), 0);
756                    count = 1;
757                }
758            }
759
760            this.ordering = o;
761            this.values = v;
762            this.added = a;
763        }
764    }
765
766    /**
767     * return a vector of the oids in the name, in the order they were found.
768     */
769    public Vector getOIDs()
770    {
771        Vector  v = new Vector();
772
773        for (int i = 0; i != ordering.size(); i++)
774        {
775            v.addElement(ordering.elementAt(i));
776        }
777
778        return v;
779    }
780
781    /**
782     * return a vector of the values found in the name, in the order they
783     * were found.
784     */
785    public Vector getValues()
786    {
787        Vector  v = new Vector();
788
789        for (int i = 0; i != values.size(); i++)
790        {
791            v.addElement(values.elementAt(i));
792        }
793
794        return v;
795    }
796
797    /**
798     * return a vector of the values found in the name, in the order they
799     * were found, with the DN label corresponding to passed in oid.
800     */
801    public Vector getValues(
802        DERObjectIdentifier oid)
803    {
804        Vector  v = new Vector();
805
806        for (int i = 0; i != values.size(); i++)
807        {
808            if (ordering.elementAt(i).equals(oid))
809            {
810                String val = (String)values.elementAt(i);
811
812                if (val.length() > 2 && val.charAt(0) == '\\' && val.charAt(1) == '#')
813                {
814                    v.addElement(val.substring(1));
815                }
816                else
817                {
818                    v.addElement(val);
819                }
820            }
821        }
822
823        return v;
824    }
825
826    public DERObject toASN1Object()
827    {
828        if (seq == null)
829        {
830            ASN1EncodableVector  vec = new ASN1EncodableVector();
831            ASN1EncodableVector  sVec = new ASN1EncodableVector();
832            DERObjectIdentifier  lstOid = null;
833
834            for (int i = 0; i != ordering.size(); i++)
835            {
836                ASN1EncodableVector     v = new ASN1EncodableVector();
837                DERObjectIdentifier     oid = (DERObjectIdentifier)ordering.elementAt(i);
838
839                v.add(oid);
840
841                String  str = (String)values.elementAt(i);
842
843                v.add(converter.getConvertedValue(oid, str));
844
845                if (lstOid == null
846                    || ((Boolean)this.added.elementAt(i)).booleanValue())
847                {
848                    sVec.add(new DERSequence(v));
849                }
850                else
851                {
852                    vec.add(new DERSet(sVec));
853                    sVec = new ASN1EncodableVector();
854
855                    sVec.add(new DERSequence(v));
856                }
857
858                lstOid = oid;
859            }
860
861            vec.add(new DERSet(sVec));
862
863            seq = new DERSequence(vec);
864        }
865
866        return seq;
867    }
868
869    /**
870     * @param inOrder if true the order of both X509 names must be the same,
871     * as well as the values associated with each element.
872     */
873    public boolean equals(Object obj, boolean inOrder)
874    {
875        if (!inOrder)
876        {
877            return this.equals(obj);
878        }
879
880        if (obj == this)
881        {
882            return true;
883        }
884
885        if (!(obj instanceof X509Name || obj instanceof ASN1Sequence))
886        {
887            return false;
888        }
889
890        DERObject derO = ((DEREncodable)obj).getDERObject();
891
892        if (this.getDERObject().equals(derO))
893        {
894            return true;
895        }
896
897        X509Name other;
898
899        try
900        {
901            other = X509Name.getInstance(obj);
902        }
903        catch (IllegalArgumentException e)
904        {
905            return false;
906        }
907
908        int      orderingSize = ordering.size();
909
910        if (orderingSize != other.ordering.size())
911        {
912            return false;
913        }
914
915        for (int i = 0; i < orderingSize; i++)
916        {
917            DERObjectIdentifier  oid = (DERObjectIdentifier)ordering.elementAt(i);
918            DERObjectIdentifier  oOid = (DERObjectIdentifier)other.ordering.elementAt(i);
919
920            if (oid.equals(oOid))
921            {
922                String value = (String)values.elementAt(i);
923                String oValue = (String)other.values.elementAt(i);
924
925                if (!equivalentStrings(value, oValue))
926                {
927                    return false;
928                }
929            }
930            else
931            {
932                return false;
933            }
934        }
935
936        return true;
937    }
938
939    public int hashCode()
940    {
941        if (isHashCodeCalculated)
942        {
943            return hashCodeValue;
944        }
945
946        isHashCodeCalculated = true;
947
948        // this needs to be order independent, like equals
949        for (int i = 0; i != ordering.size(); i += 1)
950        {
951            String value = (String)values.elementAt(i);
952
953            value = canonicalize(value);
954            value = stripInternalSpaces(value);
955
956            hashCodeValue ^= ordering.elementAt(i).hashCode();
957            hashCodeValue ^= value.hashCode();
958        }
959
960        return hashCodeValue;
961    }
962
963    /**
964     * test for equality - note: case is ignored.
965     */
966    public boolean equals(Object obj)
967    {
968        if (obj == this)
969        {
970            return true;
971        }
972
973        if (!(obj instanceof X509Name || obj instanceof ASN1Sequence))
974        {
975            return false;
976        }
977
978        DERObject derO = ((DEREncodable)obj).getDERObject();
979
980        if (this.getDERObject().equals(derO))
981        {
982            return true;
983        }
984
985        X509Name other;
986
987        try
988        {
989            other = X509Name.getInstance(obj);
990        }
991        catch (IllegalArgumentException e)
992        {
993            return false;
994        }
995
996        int      orderingSize = ordering.size();
997
998        if (orderingSize != other.ordering.size())
999        {
1000            return false;
1001        }
1002
1003        boolean[] indexes = new boolean[orderingSize];
1004        int       start, end, delta;
1005
1006        if (ordering.elementAt(0).equals(other.ordering.elementAt(0)))   // guess forward
1007        {
1008            start = 0;
1009            end = orderingSize;
1010            delta = 1;
1011        }
1012        else  // guess reversed - most common problem
1013        {
1014            start = orderingSize - 1;
1015            end = -1;
1016            delta = -1;
1017        }
1018
1019        for (int i = start; i != end; i += delta)
1020        {
1021            boolean              found = false;
1022            DERObjectIdentifier  oid = (DERObjectIdentifier)ordering.elementAt(i);
1023            String               value = (String)values.elementAt(i);
1024
1025            for (int j = 0; j < orderingSize; j++)
1026            {
1027                if (indexes[j])
1028                {
1029                    continue;
1030                }
1031
1032                DERObjectIdentifier oOid = (DERObjectIdentifier)other.ordering.elementAt(j);
1033
1034                if (oid.equals(oOid))
1035                {
1036                    String oValue = (String)other.values.elementAt(j);
1037
1038                    if (equivalentStrings(value, oValue))
1039                    {
1040                        indexes[j] = true;
1041                        found      = true;
1042                        break;
1043                    }
1044                }
1045            }
1046
1047            if (!found)
1048            {
1049                return false;
1050            }
1051        }
1052
1053        return true;
1054    }
1055
1056    private boolean equivalentStrings(String s1, String s2)
1057    {
1058        String value = canonicalize(s1);
1059        String oValue = canonicalize(s2);
1060
1061        if (!value.equals(oValue))
1062        {
1063            value = stripInternalSpaces(value);
1064            oValue = stripInternalSpaces(oValue);
1065
1066            if (!value.equals(oValue))
1067            {
1068                return false;
1069            }
1070        }
1071
1072        return true;
1073    }
1074
1075    private String canonicalize(String s)
1076    {
1077        String value = Strings.toLowerCase(s.trim());
1078
1079        if (value.length() > 0 && value.charAt(0) == '#')
1080        {
1081            DERObject obj = decodeObject(value);
1082
1083            if (obj instanceof DERString)
1084            {
1085                value = Strings.toLowerCase(((DERString)obj).getString().trim());
1086            }
1087        }
1088
1089        return value;
1090    }
1091
1092    private ASN1Object decodeObject(String oValue)
1093    {
1094        try
1095        {
1096            return ASN1Object.fromByteArray(Hex.decode(oValue.substring(1)));
1097        }
1098        catch (IOException e)
1099        {
1100            throw new IllegalStateException("unknown encoding in name: " + e);
1101        }
1102    }
1103
1104    private String stripInternalSpaces(
1105        String str)
1106    {
1107        StringBuffer res = new StringBuffer();
1108
1109        if (str.length() != 0)
1110        {
1111            char    c1 = str.charAt(0);
1112
1113            res.append(c1);
1114
1115            for (int k = 1; k < str.length(); k++)
1116            {
1117                char    c2 = str.charAt(k);
1118                if (!(c1 == ' ' && c2 == ' '))
1119                {
1120                    res.append(c2);
1121                }
1122                c1 = c2;
1123            }
1124        }
1125
1126        return res.toString();
1127    }
1128
1129    private void appendValue(
1130        StringBuffer        buf,
1131        Hashtable           oidSymbols,
1132        DERObjectIdentifier oid,
1133        String              value)
1134    {
1135        String  sym = (String)oidSymbols.get(oid);
1136
1137        if (sym != null)
1138        {
1139            buf.append(sym);
1140        }
1141        else
1142        {
1143            buf.append(oid.getId());
1144        }
1145
1146        buf.append('=');
1147
1148        int     index = buf.length();
1149
1150        buf.append(value);
1151
1152        int     end = buf.length();
1153
1154        if (value.length() >= 2 && value.charAt(0) == '\\' && value.charAt(1) == '#')
1155        {
1156            index += 2;
1157        }
1158
1159        while (index != end)
1160        {
1161            if ((buf.charAt(index) == ',')
1162               || (buf.charAt(index) == '"')
1163               || (buf.charAt(index) == '\\')
1164               || (buf.charAt(index) == '+')
1165               || (buf.charAt(index) == '=')
1166               || (buf.charAt(index) == '<')
1167               || (buf.charAt(index) == '>')
1168               || (buf.charAt(index) == ';'))
1169            {
1170                buf.insert(index, "\\");
1171                index++;
1172                end++;
1173            }
1174
1175            index++;
1176        }
1177    }
1178
1179    /**
1180     * convert the structure to a string - if reverse is true the
1181     * oids and values are listed out starting with the last element
1182     * in the sequence (ala RFC 2253), otherwise the string will begin
1183     * with the first element of the structure. If no string definition
1184     * for the oid is found in oidSymbols the string value of the oid is
1185     * added. Two standard symbol tables are provided DefaultSymbols, and
1186     * RFC2253Symbols as part of this class.
1187     *
1188     * @param reverse if true start at the end of the sequence and work back.
1189     * @param oidSymbols look up table strings for oids.
1190     */
1191    public String toString(
1192        boolean     reverse,
1193        Hashtable   oidSymbols)
1194    {
1195        StringBuffer            buf = new StringBuffer();
1196        Vector                  components = new Vector();
1197        boolean                 first = true;
1198
1199        StringBuffer ava = null;
1200
1201        for (int i = 0; i < ordering.size(); i++)
1202        {
1203            if (((Boolean)added.elementAt(i)).booleanValue())
1204            {
1205                ava.append('+');
1206                appendValue(ava, oidSymbols,
1207                    (DERObjectIdentifier)ordering.elementAt(i),
1208                    (String)values.elementAt(i));
1209            }
1210            else
1211            {
1212                ava = new StringBuffer();
1213                appendValue(ava, oidSymbols,
1214                    (DERObjectIdentifier)ordering.elementAt(i),
1215                    (String)values.elementAt(i));
1216                components.addElement(ava);
1217            }
1218        }
1219
1220        if (reverse)
1221        {
1222            for (int i = components.size() - 1; i >= 0; i--)
1223            {
1224                if (first)
1225                {
1226                    first = false;
1227                }
1228                else
1229                {
1230                    buf.append(',');
1231                }
1232
1233                buf.append(components.elementAt(i).toString());
1234            }
1235        }
1236        else
1237        {
1238            for (int i = 0; i < components.size(); i++)
1239            {
1240                if (first)
1241                {
1242                    first = false;
1243                }
1244                else
1245                {
1246                    buf.append(',');
1247                }
1248
1249                buf.append(components.elementAt(i).toString());
1250            }
1251        }
1252
1253        return buf.toString();
1254    }
1255
1256    private String bytesToString(
1257        byte[] data)
1258    {
1259        char[]  cs = new char[data.length];
1260
1261        for (int i = 0; i != cs.length; i++)
1262        {
1263            cs[i] = (char)(data[i] & 0xff);
1264        }
1265
1266        return new String(cs);
1267    }
1268
1269    public String toString()
1270    {
1271        return toString(DefaultReverse, DefaultSymbols);
1272    }
1273}
1274