diff options
Diffstat (limited to 'base/util/src/netscape/security/x509/X500Name.java')
-rw-r--r-- | base/util/src/netscape/security/x509/X500Name.java | 757 |
1 files changed, 757 insertions, 0 deletions
diff --git a/base/util/src/netscape/security/x509/X500Name.java b/base/util/src/netscape/security/x509/X500Name.java new file mode 100644 index 000000000..c8bd8ed6a --- /dev/null +++ b/base/util/src/netscape/security/x509/X500Name.java @@ -0,0 +1,757 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; version 2 of the License. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- +package netscape.security.x509; + +import java.io.StringReader; +import java.io.IOException; +import java.io.StringBufferInputStream; +import java.security.Principal; +import java.util.Enumeration; +import java.util.Vector; + +import netscape.security.util.*; + + +/** + * X.500 names are used to identify entities, such as those which are + * identified by X.509 certificates. They are world-wide, hierarchical, + * and descriptive. Entities can be identified by attributes, and in + * some systems can be searched for according to those attributes. + * + * <P><em>This class exposes only partial X.500 name functionality. Most + * notably, it works best if Relative Distinguished Names only have one + * (unique) attribute each, and if only the most common attributes need + * to be visible to applications. This limitation, and others, will + * be lifted over time.</em> + * + * @author David Brownell + * @author Amit Kapoor + * @author Hemma Prafullchandra + * @version 1.35 + * @see GeneralName + * @see GeneralNames + * @see GeneralNameInterface + * @see RDN + * @see AVA + * @see LdapDNStrConverter + */ + + +public class X500Name implements Principal, GeneralNameInterface { + /** + * Constructs a name from a Ldap DN string, such + * as &lb;CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US&rb;. The + * older "/C=US/O=Sun Microsystems, Inc/OU=JavaSoft/CN=Dave" syntax + * is not currently supported. (The former is RFC 1779 style.) + * + * @param ldapDNString a Ldap DN String e.g. as defined in RFC1779 + */ + public X500Name (String ldapDNString) + throws IOException + { + X500Name x500name; + + if(ldapDNString == null || ldapDNString.equals("")) + { + clear(); + return; + } + x500name = LdapDNStrConverter.getDefault().parseDN(ldapDNString); + names = x500name.getNames(); + } + + /** + * Constructs a X500Name from a Ldap DN String using the specified + * LdapDNStrConverter. Also use the input tags. + * @see LdapDNStrConverter + * + * @param ldapDNString a Ldap DN String e.g. as defined in RFC1779. + * @param ldapDNStrConverter A LdapDNStrConverter + */ + public X500Name (String ldapDNString,LdapDNStrConverter ldapDNStrConverter,byte[] tags) + throws IOException + { + + if(ldapDNString == null || ldapDNString.equals("")) + { + clear(); + return; + } + X500Name x500name; + x500name = ldapDNStrConverter.parseDN(ldapDNString,tags); + names = x500name.getNames(); + + } + + public X500Name (String ldapDNString, byte[] tags) + throws IOException + { + if(ldapDNString == null || ldapDNString.equals("")) + { + clear(); + return; + } + X500Name x500name; + x500name = LdapDNStrConverter.getDefault().parseDN(ldapDNString, tags); + names = x500name.getNames(); + } + + /** + * Constructs a X500Name from a Ldap DN String using the specified + * LdapDNStrConverter. + * @see LdapDNStrConverter + * + * @param ldapDNString a Ldap DN String e.g. as defined in RFC1779. + * @param ldapDNStrConverter A LdapDNStrConverter + */ + public X500Name (String ldapDNString, + LdapDNStrConverter ldapDNStrConverter) + throws IOException + { + if(ldapDNString == null || ldapDNString.equals("")) + { + clear(); + return; + } + X500Name x500name; + x500name = ldapDNStrConverter.parseDN(ldapDNString); + names = x500name.getNames(); + } + + /** + * Constructs a X500Name from fields common in enterprise application + * environments. + * + * @param commonName common name of a person, e.g. "Vivette Davis" + * @param organizationUnit small organization name, e.g. "Purchasing" + * @param organizationName large organization name, e.g. "Onizuka, Inc." + * @param country two letter country code, e.g. "CH" + */ + public X500Name ( + String commonName, + String organizationUnit, + String organizationName, + String country + ) throws IOException + { + DirStrConverter dirStrConverter = new DirStrConverter(); + PrintableConverter printableConverter = new PrintableConverter(); + DerValue val; + AVA[] assertion = new AVA[1]; // array is cloned in constructors. + int i = 4; + + names = new RDN [i]; + /* + * NOTE: it's only on output that little-endian + * ordering is used. + */ + assertion[0] = new AVA(commonName_oid, + dirStrConverter.getValue(commonName)); + names [--i] = new RDN (assertion); + + assertion[0] = new AVA(orgUnitName_oid, + dirStrConverter.getValue(organizationUnit)); + names [--i] = new RDN (assertion); + + assertion[0] = new AVA(orgName_oid, + dirStrConverter.getValue(organizationName)); + names [--i] = new RDN (assertion); + + assertion[0] = new AVA(countryName_oid, + printableConverter.getValue(country)); + names [--i] = new RDN (assertion); + } + + /** + * Constructs a X500Name from fields common in Internet application + * environments. + * + * @param commonName common name of a person, e.g. "Vivette Davis" + * @param organizationUnit small organization name, e.g. "Purchasing" + * @param organizationName large organization name, e.g. "Onizuka, Inc." + * @param localityName locality (city) name, e.g. "Palo Alto" + * @param stateName state name, e.g. "California" + * @param country two letter country code, e.g. "CH" + */ + public X500Name ( + String commonName, + String organizationUnit, + String organizationName, + String localityName, + String stateName, + String country + ) throws IOException + { + DirStrConverter dirStrConverter = new DirStrConverter(); + PrintableConverter printableConverter = new PrintableConverter(); + DerValue val; + AVA[] assertion = new AVA[1]; // array is cloned in constructors. + int i = 6; + + names = new RDN [i]; + /* + * NOTE: it's only on output that little-endian + * ordering is used. + */ + assertion[0] = new AVA(commonName_oid, + dirStrConverter.getValue(commonName)); + names [--i] = new RDN (assertion); + + assertion[0] = new AVA(orgUnitName_oid, + dirStrConverter.getValue(organizationUnit)); + names [--i] = new RDN (assertion); + + assertion[0] = new AVA(orgName_oid, + dirStrConverter.getValue(organizationName)); + names [--i] = new RDN (assertion); + + assertion[0] = new AVA(localityName_oid, + dirStrConverter.getValue(localityName)); + names [--i] = new RDN (assertion); + + assertion[0] = new AVA(stateName_oid, + dirStrConverter.getValue(stateName)); + names [--i] = new RDN (assertion); + + assertion[0] = new AVA(countryName_oid, + printableConverter.getValue(country)); + names [--i] = new RDN (assertion); + } + + + /** + * Constructs a name from an ASN.1 encoded value. The encoding + * of the name in the stream uses DER (a BER/1 subset). + * + * @param value a DER-encoded value holding an X.500 name. + */ + public X500Name(DerValue value) throws IOException { + + this(value.toDerInputStream()); + } + + /** + * Constructs a name from an ASN.1 encoded input stream. The encoding + * of the name in the stream uses DER (a BER/1 subset). + * + * @param in DER-encoded data holding an X.500 name. + */ + public X500Name (DerInputStream in) + throws IOException + { + parseDER (in); + } + + /** + * Constructs a name from an ASN.1 encoded byte array. + * + * @param name DER-encoded byte array holding an X.500 name. + */ + public X500Name (byte[] name) + throws IOException + { + DerInputStream in = new DerInputStream(name); + parseDER (in); + + } + + /** + * Constructs a X500Name from array of RDN. The RDNs are expected to + * be in big endian order i.e. most significant first. + * @param rdns an array of RDN. + */ + public X500Name (RDN[] rdns) + throws IOException + { + names = (RDN[])rdns.clone(); + } + + /** + * convenience method. + * @param rdns a vector of rdns. + */ + public X500Name (Vector rdnVector) + throws IOException + { + int size = rdnVector.size(); + names = new RDN[size]; + for (int i = 0; i < size; i++) { + names[i] = (RDN)rdnVector.elementAt(i); + } + } + + /** + * Compares this name with another, for equality. + * + * @return true iff the names are identical. + */ + synchronized public boolean equals (X500Name other) + { + int i; + + if (this == other) + return true; + + if (names.length != other.names.length) + return false; + for (i = 0; i < names.length; i++) { + if (!names [i].equals (other.names [i])) + return false; + } + return true; + } + + /** + * Sets private data to a null state + */ + + private void clear() + { + dn = ""; + names = null; + + } + + /** + * Returns the name component as a Java string, regardless of its + * encoding restrictions. + */ + private String getString (DerValue attribute) throws IOException + { + String value = attribute.getAsString (); + + if (value == null) + throw new IOException ("not a DER string encoding, " + + attribute.tag); + else + return value; + } + + /** + * Return type of GeneralName. + */ + public int getType() { + return (GeneralNameInterface.NAME_DIRECTORY); + } + + /** + * Returns a "Country" name component. If more than one + * such attribute exists, the topmost one is returned. + * + * @return "C=" component of the name, if any. + */ + public String getCountry () throws IOException + { + DerValue attr = findAttribute (countryName_oid); + + return getString (attr); + } + + + /** + * Returns an "Organization" name component. If more than + * one such attribute exists, the topmost one is returned. + * + * @return "O=" component of the name, if any. + */ + public String getOrganization () throws IOException + { + DerValue attr = findAttribute (orgName_oid); + + return getString (attr); + } + + + /** + * Returns an "Organizational Unit" name component. If more + * than one such attribute exists, the topmost one is returned. + * + * @return "OU=" component of the name, if any. + */ + public String getOrganizationalUnit () throws IOException + { + DerValue attr = findAttribute (orgUnitName_oid); + + return getString (attr); + } + + + /** + * Returns a "Common Name" component. If more than one such + * attribute exists, the topmost one is returned. + * + * @return "CN=" component of the name, if any. + */ + public String getCommonName () throws IOException + { + DerValue attr = findAttribute (commonName_oid); + + return getString (attr); + } + + + /** + * Returns a "UID" component. If more than one such + * attribute exists, the topmost one is returned. + * + * @return "UID=" component of the name, if any. + */ + public String getUserID () throws IOException + { + DerValue attr = findAttribute (uidName_oid); + + return getString (attr); + } + + + /** + * Returns a "Locality" name component. If more than one + * such component exists, the topmost one is returned. + * + * @return "L=" component of the name, if any. + */ + public String getLocality () throws IOException + { + DerValue attr = findAttribute (localityName_oid); + + return getString (attr); + } + + + /** + * Returns a "State" name component. If more than one + * such component exists, the topmost one is returned. + * + * @return "S=" component of the name, if any. + */ + public String getState () throws IOException + { + DerValue attr = findAttribute (stateName_oid); + + return getString (attr); + } + + /** + * Returns a "Email" name component. If more than one + * such component exists, the topmost one is returned. + * + * @return "E=" component of the name, if any. + */ + public String getEmail() throws IOException + { + DerValue attr = findAttribute (email_oid); + if (attr == null) + return null; + return getString (attr); + } + + /** + * Returns a Ldap DN String from the X500Name using the global default + * LdapDNStrConverter + * @see LdapDNStrConverter + * @return Ldap DN string of this X500Name using the default converter. + */ + public String toLdapDNString() + throws IOException + { + if (dn == null) + generateDN(LdapDNStrConverter.getDefault()); + return dn; + } + + /** + * Returns a Ldap DN String from the X500Name + * using the specified LdapDNStrconverter. + * For example, RFC1779String converter can be passed to convert the + * DN to RFC1779 string syntax. + * @see LdapDNStrConverter + * @param ldapDNStrConverter a LdapDNStrConverter + * @return Ldap DN string of the X500Name + */ + public String toLdapDNString(LdapDNStrConverter ldapDNStrConverter) + throws IOException + { + + if (dn == null) + generateDN(ldapDNStrConverter); + return dn; + } + + /** + * Returns a Ldap DN string, using the global default LdapDNStrConverter + * or null if an error occurs in the conversion. + */ + public String toString() + { + String s; + if(names == null) + { + s = ""; + return s; + } + try { + s = toLdapDNString(); + } + catch (IOException e) { + return null; + } + return s; + } + + /** + * Returns the value of toString(). This call is needed to + * implement the java.security.Principal interface. + */ + public String getName () { return toString (); } + + + private String dn; // RFC 1779 style DN, or null + private RDN names[]; // RDNs + + /** + * Find the first instance of this attribute in a "top down" + * search of all the attributes in the name. + */ + private DerValue findAttribute (ObjectIdentifier attribute) + { + int i; + DerValue retval = null; + + for (i = 0; i < names.length; i++) { + retval = names [i].findAttribute (attribute); + if (retval != null) + break; + } + return retval; + } + + /** + * Returns an enumerator of RDNs in the X500Name. + * @return enumeration of rdns in this X500Name. + */ + public Enumeration getRDNs() + { + return new RDNEnumerator(); + } + + /** + * Returns an array of RDN in the X500Name. + * @return array of RDN in this X500name. + */ + public RDN[] getNames() + { + return (RDN[])names.clone(); + } + + /** + * Returns the number of RDNs in the X500Name. + * @return number of RDNs in this X500Name. + */ + public int getNamesLength() + { + return names.length; + } + + /****************************************************************/ + + private void parseDER (DerInputStream in) throws IOException + { + // + // X.500 names are a "SEQUENCE OF" RDNs, which means one or + // more and order matters. We scan them in order, which + // conventionally is big-endian. + // + DerValue nameseq [] = in.getSequence (5); + int i; + + if(nameseq.length != 0) + { + names = new RDN [nameseq.length]; + } + else + { + clear(); + } + + + for (i = 0; i < nameseq.length; i++) + names [i] = new RDN (nameseq [i]); + } + + /** + * Encodes the name in DER-encoded form. + * + * @param out where to put the DER-encoded X.500 name + */ + public void encode (DerOutputStream out) throws IOException + { + DerOutputStream tmp = new DerOutputStream (); + int i; + + int len = 0; + if(names == null) + { + len = 0; + } + else + { + len = names.length; + + } + + for (i = 0; i < len; i++) + names [i].encode (tmp); + + out.write (DerValue.tag_Sequence, tmp); + } + + /** + * Gets the name in DER-encoded form. + * + * @return the DER encoded byte array of this name, + * null if no names are present. + */ + public byte[] getEncoded() throws IOException { + + DerOutputStream out = new DerOutputStream(); + DerOutputStream tmp = new DerOutputStream(); + + int len = 0; + + if (names == null) + { + len = 0; + } + else + { + len = names.length; + } + + for (int i = 0; i < len; i++) + names[i].encode(tmp); + + out.write(DerValue.tag_Sequence, tmp); + return out.toByteArray(); + } + + /* + * Dump the printable form of a distinguished name. Each relative + * name is separated from the next by a ",", and assertions in the + * relative names have "label=value" syntax. + * + * Uses RFC 1779 syntax (i.e. little-endian, comma separators) + * + */ + private void generateDN(LdapDNStrConverter ldapDNStrConverter) + throws IOException + { + if(names == null) + return ; + + dn = ldapDNStrConverter.encodeDN(this); + } + + private class RDNEnumerator implements Enumeration + { + private int index; + + public RDNEnumerator() { index = 0; } + + public boolean hasMoreElements() + { + return (index < names.length); + } + + public Object nextElement() + { + if (index >= names.length) + return null; + return names[index++]; + } + } + + /****************************************************************/ + + /* + * Maybe return a preallocated OID, to reduce storage costs + * and speed recognition of common X.500 attributes. + */ + static ObjectIdentifier intern (ObjectIdentifier oid) + throws IOException + { + return X500NameAttrMap.getDefault().getOid(oid); + } + + /* + * Selected OIDs from X.520 + */ + + /** OID for the "CN=" attribute, denoting a person's common name. */ + public static final ObjectIdentifier + commonName_oid = X500NameAttrMap.getDefault().getOid("CN"); + + /** OID for the "UID=" attribute, denoting a person's ID. */ + public static final ObjectIdentifier + uidName_oid = X500NameAttrMap.getDefault().getOid("UID"); + + /** OID for the "C=" attribute, denoting a country. */ + public static final ObjectIdentifier + countryName_oid = X500NameAttrMap.getDefault().getOid("C"); + + /** OID for the "L=" attribute, denoting a locality (such as a city) */ + public static final ObjectIdentifier + localityName_oid = X500NameAttrMap.getDefault().getOid("L"); + + /** OID for the "O=" attribute, denoting an organization name */ + public static final ObjectIdentifier + orgName_oid = X500NameAttrMap.getDefault().getOid("O"); + + /** OID for the "OU=" attribute, denoting an organizational unit name */ + public static final ObjectIdentifier + orgUnitName_oid = X500NameAttrMap.getDefault().getOid("OU"); + + /** OID for the "S=" attribute, denoting a state (such as Delaware) */ + public static final ObjectIdentifier + stateName_oid = X500NameAttrMap.getDefault().getOid("ST"); + + /** OID for the "STREET=" attribute, denoting a street address. */ + public static final ObjectIdentifier + streetAddress_oid = X500NameAttrMap.getDefault().getOid("STREET"); + + /** OID for the "T=" attribute, denoting a person's title. */ + public static final ObjectIdentifier + title_oid = X500NameAttrMap.getDefault().getOid("TITLE"); + + /** OID for the "E=" attribute, denoting a person's email address. */ + public static final ObjectIdentifier + email_oid = X500NameAttrMap.getDefault().getOid("E"); + + /* + * OIDs from other sources which show up in X.500 names we + * expect to deal with often + */ + + private static final int ipAddress_data [] = // SKIP + { 1, 3, 6, 1, 4, 1, 42, 2, 11, 2, 1 }; + + /** OID for "IP=" IP address attributes, used with SKIP. */ + public static final ObjectIdentifier + ipAddress_oid = new ObjectIdentifier (ipAddress_data); +} + + |