Home | History | Annotate | Download | only in x509
      1 package org.bouncycastle.asn1.x509;
      2 
      3 import java.io.IOException;
      4 import java.util.Enumeration;
      5 import java.util.Hashtable;
      6 import java.util.Vector;
      7 
      8 import org.bouncycastle.asn1.ASN1Encodable;
      9 import org.bouncycastle.asn1.ASN1EncodableVector;
     10 import org.bouncycastle.asn1.ASN1Object;
     11 import org.bouncycastle.asn1.ASN1Sequence;
     12 import org.bouncycastle.asn1.ASN1Set;
     13 import org.bouncycastle.asn1.ASN1TaggedObject;
     14 import org.bouncycastle.asn1.DEREncodable;
     15 import org.bouncycastle.asn1.DERObject;
     16 import org.bouncycastle.asn1.DERObjectIdentifier;
     17 import org.bouncycastle.asn1.DERSequence;
     18 import org.bouncycastle.asn1.DERSet;
     19 import org.bouncycastle.asn1.DERString;
     20 import org.bouncycastle.asn1.DERUniversalString;
     21 import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
     22 import org.bouncycastle.asn1.x500.X500Name;
     23 import org.bouncycastle.util.Strings;
     24 import 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  */
     38 public 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