--- /dev/null
+package org.bouncycastle.asn1.x509;
+
+import java.io.*;
+import java.util.*;
+
+import org.bouncycastle.asn1.*;
+
+public class X509Name
+ implements DEREncodable
+{
+ /**
+ * country code - StringType(SIZE(2))
+ */
+ public static final DERObjectIdentifier C = new DERObjectIdentifier("2.5.4.6");
+
+ /**
+ * organization - StringType(SIZE(1..64))
+ */
+ public static final DERObjectIdentifier O = new DERObjectIdentifier("2.5.4.10");
+
+ /**
+ * organizational unit name - StringType(SIZE(1..64))
+ */
+ public static final DERObjectIdentifier OU = new DERObjectIdentifier("2.5.4.11");
+
+ /**
+ * common name - StringType(SIZE(1..64))
+ */
+ public static final DERObjectIdentifier CN = new DERObjectIdentifier("2.5.4.3");
+
+ /**
+ * device serial number name - StringType(SIZE(1..64))
+ */
+ public static final DERObjectIdentifier SN = new DERObjectIdentifier("2.5.4.5");
+
+ /**
+ * locality name - StringType(SIZE(1..64))
+ */
+ public static final DERObjectIdentifier L = new DERObjectIdentifier("2.5.4.7");
+
+ /**
+ * state, or province name - StringType(SIZE(1..64))
+ */
+ public static final DERObjectIdentifier ST = new DERObjectIdentifier("2.5.4.8");
+
+ /**
+ * email address (RSA PKCS#9 extension) - IA5String
+ * <p>
+ * note: if you're trying to be ultra orthodox, don't use this! It shouldn't be in here.
+ */
+ public static final DERObjectIdentifier EmailAddress = new DERObjectIdentifier("1.2.840.113549.1.9.1");
+
+ /**
+ * look up table translating OID values into their common symbols.
+ */
+ public static Hashtable OIDLookUp = new Hashtable();
+
+ /**
+ * look up table translating common symbols into their OIDS.
+ */
+ public static Hashtable SymbolLookUp = new Hashtable();
+
+ static
+ {
+ OIDLookUp.put(C, "C");
+ OIDLookUp.put(O, "O");
+ OIDLookUp.put(OU, "OU");
+ OIDLookUp.put(CN, "CN");
+ OIDLookUp.put(L, "L");
+ OIDLookUp.put(ST, "ST");
+ OIDLookUp.put(SN, "SN");
+ OIDLookUp.put(EmailAddress, "EmailAddress");
+
+ SymbolLookUp.put("C", C);
+ SymbolLookUp.put("O", O);
+ SymbolLookUp.put("OU", OU);
+ SymbolLookUp.put("CN", CN);
+ SymbolLookUp.put("L", L);
+ SymbolLookUp.put("ST", ST);
+ SymbolLookUp.put("SN", SN);
+ SymbolLookUp.put("EmailAddress", EmailAddress);
+ }
+
+ private Vector ordering = new Vector();
+ private Hashtable attributes = new Hashtable();
+ private DERConstructedSequence seq = null;
+
+ /**
+ * Constructor from DERConstructedSequence.
+ *
+ * the principal will be a list of constructed sets, each containing an (OID, String) pair.
+ */
+ public X509Name(
+ DERConstructedSequence seq)
+ {
+ this.seq = seq;
+
+ Enumeration e = seq.getObjects();
+
+ while (e.hasMoreElements())
+ {
+ DERSet set = (DERSet)e.nextElement();
+ DERConstructedSequence s = (DERConstructedSequence)set.getSequence();
+
+ ordering.addElement(s.getObjectAt(0));
+ attributes.put(s.getObjectAt(0), ((DERString)s.getObjectAt(1)).getString());
+ }
+ }
+
+ /**
+ * constructor from a table of attributes.
+ * <p>
+ * it's is assumed the table contains OID/String pairs, and the contents
+ * of the table are copied into an internal table as part of the
+ * construction process.
+ * <p>
+ * <b>Note:</b> if the name you are trying to generate should be
+ * following a specific ordering, you should use the constructor
+ * with the ordering specified below.
+ */
+ public X509Name(
+ Hashtable attributes)
+ {
+ this(null, attributes);
+ }
+
+ /**
+ * constructor from a table of attributes with ordering.
+ * <p>
+ * it's is assumed the table contains OID/String pairs, and the contents
+ * of the table are copied into an internal table as part of the
+ * construction process. The ordering vector should contain the OIDs
+ * in the order they are meant to be encoded or printed in toString.
+ */
+ public X509Name(
+ Vector ordering,
+ Hashtable attributes)
+ {
+ if (ordering != null)
+ {
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ this.ordering.addElement(ordering.elementAt(i));
+ }
+ }
+ else
+ {
+ Enumeration e = attributes.keys();
+
+ while (e.hasMoreElements())
+ {
+ this.ordering.addElement(e.nextElement());
+ }
+ }
+
+ for (int i = 0; i != this.ordering.size(); i++)
+ {
+ DERObjectIdentifier oid = (DERObjectIdentifier)this.ordering.elementAt(i);
+
+ if (OIDLookUp.get(oid) == null)
+ {
+ throw new IllegalArgumentException("Unknown object id - " + oid.getId() + " - passed to distinguished name");
+ }
+
+ if (attributes.get(oid) == null)
+ {
+ throw new IllegalArgumentException("No attribute for object id - " + oid.getId() + " - passed to distinguished name");
+ }
+
+ this.attributes.put(oid, attributes.get(oid)); // copy the hash table
+ }
+ }
+
+ /**
+ * takes an X509 dir name as a string of the format "C=AU, ST=Victoria", or
+ * some such, converting it into an ordered set of name attributes.
+ */
+ public X509Name(
+ String dirName)
+ {
+ X509NameTokenizer nTok = new X509NameTokenizer(dirName);
+
+ while (nTok.hasMoreTokens())
+ {
+ String token = nTok.nextToken();
+ int index = token.indexOf('=');
+
+ if (index == -1)
+ {
+ throw new IllegalArgumentException("badly formated directory string");
+ }
+
+ String name = token.substring(0, index);
+ String value = token.substring(index + 1);
+
+ DERObjectIdentifier oid = (DERObjectIdentifier)SymbolLookUp.get(name);
+ if (oid == null)
+ {
+ throw new IllegalArgumentException("Unknown object id - " + oid.getId() + " - passed to distinguished name");
+ }
+
+ this.ordering.addElement(oid);
+ this.attributes.put(oid, value);
+ }
+ }
+
+ public DERObject getDERObject()
+ {
+ if (seq == null)
+ {
+ seq = new DERConstructedSequence();
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ DERConstructedSequence s = new DERConstructedSequence();
+ DERObjectIdentifier oid = (DERObjectIdentifier)ordering.elementAt(i);
+
+ s.addObject(oid);
+ if (oid.equals(EmailAddress))
+ {
+ s.addObject(new DERIA5String((String)attributes.get(oid)));
+ }
+ else
+ {
+ s.addObject(new DERPrintableString((String)attributes.get(oid)));
+ }
+
+ seq.addObject(new DERSet(s));
+ }
+ }
+
+ return seq;
+ }
+
+ public int hashCode()
+ {
+ Enumeration e = attributes.keys();
+ int hashCode = 0;
+
+ while (e.hasMoreElements())
+ {
+ Object o = e.nextElement();
+
+ hashCode ^= o.hashCode();
+ hashCode ^= attributes.get(o).hashCode();
+ }
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ hashCode ^= ordering.elementAt(i).hashCode();
+ }
+
+ return hashCode;
+ }
+
+ public boolean equals(
+ Object o)
+ {
+ if (o == null || !(o instanceof X509Name))
+ {
+ return false;
+ }
+
+ X509Name other = (X509Name)o;
+
+ if (ordering.size() != other.ordering.size())
+ {
+ return false;
+ }
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ if (!ordering.elementAt(i).equals(other.ordering.elementAt(i)))
+ {
+ return false;
+ }
+ }
+
+ Enumeration e1 = attributes.keys();
+ Enumeration e2 = other.attributes.keys();
+
+ while (e1.hasMoreElements() && e2.hasMoreElements())
+ {
+ Object o1 = e1.nextElement();
+ Object o2 = e2.nextElement();
+
+ if (!o1.equals(o2))
+ {
+ return false;
+ }
+ }
+
+ if (e1.hasMoreElements() || e2.hasMoreElements())
+ {
+ return false;
+ }
+
+ return true;
+ }
+
+ public String toString()
+ {
+ StringBuffer buf = new StringBuffer();
+ boolean first = true;
+
+ for (int i = 0; i != ordering.size(); i++)
+ {
+ Object oid = ordering.elementAt(i);
+ String sym = (String)OIDLookUp.get(oid);
+
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ buf.append(", ");
+ }
+
+ if (sym != null)
+ {
+ buf.append(sym);
+ buf.append("=");
+ buf.append((String)attributes.get(oid));
+ }
+ else
+ {
+ buf.append(((DERObjectIdentifier)oid).getId());
+ buf.append("=");
+ buf.append((String)attributes.get(oid));
+ }
+ }
+
+ return buf.toString();
+ }
+}