1442 lines · 48.2 KB · Java
RawDownload
/* * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.security.x509; import java.lang.reflect.*;import java.io.IOException;import java.io.StringReader;import java.security.PrivilegedExceptionAction;import java.security.AccessController;import java.security.Principal;import java.util.*; import sun.security.util.*;import sun.security.pkcs.PKCS9Attribute;import javax.security.auth.x500.X500Principal; /** * Note:  As of 1.4, the public class, * javax.security.auth.x500.X500Principal, * should be used when parsing, generating, and comparing X.500 DNs. * This class contains other useful methods for checking name constraints * and retrieving DNs by keyword. * * <p> 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> * The ASN.1 for this is: * <pre> * GeneralName ::= CHOICE { * .... *     directoryName                   [4]     Name, * .... * Name ::= CHOICE { *   RDNSequence } * * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName * * RelativeDistinguishedName ::= *   SET OF AttributeTypeAndValue * * AttributeTypeAndValue ::= SEQUENCE { *   type     AttributeType, *   value    AttributeValue } * * AttributeType ::= OBJECT IDENTIFIER * * AttributeValue ::= ANY DEFINED BY AttributeType * .... * DirectoryString ::= CHOICE { *       teletexString           TeletexString (SIZE (1..MAX)), *       printableString         PrintableString (SIZE (1..MAX)), *       universalString         UniversalString (SIZE (1..MAX)), *       utf8String              UTF8String (SIZE (1.. MAX)), *       bmpString               BMPString (SIZE (1..MAX)) } * </pre> * <p> * This specification requires only a subset of the name comparison * functionality specified in the X.500 series of specifications.  The * requirements for conforming implementations are as follows: * <ol TYPE=a> * <li>attribute values encoded in different types (e.g., *    PrintableString and BMPString) may be assumed to represent *    different strings; * <p> * <li>attribute values in types other than PrintableString are case *    sensitive (this permits matching of attribute values as binary *    objects); * <p> * <li>attribute values in PrintableString are not case sensitive *    (e.g., "Marianne Swanson" is the same as "MARIANNE SWANSON"); and * <p> * <li>attribute values in PrintableString are compared after *    removing leading and trailing white space and converting internal *    substrings of one or more consecutive white space characters to a *    single space. * </ol> * <p> * These name comparison rules permit a certificate user to validate * certificates issued using languages or encodings unfamiliar to the * certificate user. * <p> * In addition, implementations of this specification MAY use these * comparison rules to process unfamiliar attribute types for name * chaining. This allows implementations to process certificates with * unfamiliar attributes in the issuer name. * <p> * Note that the comparison rules defined in the X.500 series of * specifications indicate that the character sets used to encode data * in distinguished names are irrelevant.  The characters themselves are * compared without regard to encoding. Implementations of the profile * are permitted to use the comparison algorithm defined in the X.500 * series.  Such an implementation will recognize a superset of name * matches recognized by the algorithm specified above. * <p> * Note that instances of this class are immutable. * * @author David Brownell * @author Amit Kapoor * @author Hemma Prafullchandra * @see GeneralName * @see GeneralNames * @see GeneralNameInterface */ public class X500Name implements GeneralNameInterface, Principal {     private String dn; // roughly RFC 1779 DN, or null    private String rfc1779Dn; // RFC 1779 compliant DN, or null    private String rfc2253Dn; // RFC 2253 DN, or null    private String canonicalDn; // canonical RFC 2253 DN or null    private RDN[] names;        // RDNs (never null)    private X500Principal x500Principal;    private byte[] encoded;     // cached immutable list of the RDNs and all the AVAs    private volatile List<RDN> rdnList;    private volatile List<AVA> allAvaList;     /**     * Constructs a name from a conventionally formatted string, such     * as "CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US".     * (RFC 1779 or RFC 2253 style).     *     * @param DN X.500 Distinguished Name     */    public X500Name(String dname) throws IOException {        this(dname, Collections.<String, String>emptyMap());    }     /**     * Constructs a name from a conventionally formatted string, such     * as "CN=Dave, OU=JavaSoft, O=Sun Microsystems, C=US".     * (RFC 1779 or RFC 2253 style).     *     * @param DN X.500 Distinguished Name     * @param keywordMap an additional keyword/OID map     */    public X500Name(String dname, Map<String, String> keywordMap)        throws IOException {        parseDN(dname, keywordMap);    }     /**     * Constructs a name from a string formatted according to format.     * Currently, the formats DEFAULT and RFC2253 are supported.     * DEFAULT is the default format used by the X500Name(String)     * constructor. RFC2253 is format strictly according to RFC2253     * without extensions.     *     * @param DN X.500 Distinguished Name     */    public X500Name(String dname, String format) throws IOException {        if (dname == null) {            throw new NullPointerException("Name must not be null");        }        if (format.equalsIgnoreCase("RFC2253")) {            parseRFC2253DN(dname);        } else if (format.equalsIgnoreCase("DEFAULT")) {            parseDN(dname, Collections.<String, String>emptyMap());        } else {            throw new IOException("Unsupported format " + format);        }    }     /**     * Constructs a name from fields common in enterprise application     * environments.     *     * <P><EM><STRONG>NOTE:</STRONG>  The behaviour when any of     * these strings contain characters outside the ASCII range     * is unspecified in currently relevant standards.</EM>     *     * @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 {        names = new RDN[4];        /*         * NOTE:  it's only on output that little-endian         * ordering is used.         */        names[3] = new RDN(1);        names[3].assertion[0] = new AVA(commonName_oid,                new DerValue(commonName));        names[2] = new RDN(1);        names[2].assertion[0] = new AVA(orgUnitName_oid,                new DerValue(organizationUnit));        names[1] = new RDN(1);        names[1].assertion[0] = new AVA(orgName_oid,                new DerValue(organizationName));        names[0] = new RDN(1);        names[0].assertion[0] = new AVA(countryName_oid,                new DerValue(country));    }     /**     * Constructs a name from fields common in Internet application     * environments.     *     * <P><EM><STRONG>NOTE:</STRONG>  The behaviour when any of     * these strings contain characters outside the ASCII range     * is unspecified in currently relevant standards.</EM>     *     * @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 {        names = new RDN[6];        /*         * NOTE:  it's only on output that little-endian         * ordering is used.         */        names[5] = new RDN(1);        names[5].assertion[0] = new AVA(commonName_oid,                new DerValue(commonName));        names[4] = new RDN(1);        names[4].assertion[0] = new AVA(orgUnitName_oid,                new DerValue(organizationUnit));        names[3] = new RDN(1);        names[3].assertion[0] = new AVA(orgName_oid,                new DerValue(organizationName));        names[2] = new RDN(1);        names[2].assertion[0] = new AVA(localityName_oid,                new DerValue(localityName));        names[1] = new RDN(1);        names[1].assertion[0] = new AVA(stateName_oid,                new DerValue(stateName));        names[0] = new RDN(1);        names[0].assertion[0] = new AVA(countryName_oid,                new DerValue(country));    }     /**     * Constructs a name from an array of relative distinguished names     *     * @param rdnArray array of relative distinguished names     * @throws IOException on error     */    public X500Name(RDN[] rdnArray) throws IOException {        if (rdnArray == null) {            names = new RDN[0];        } else {            names = rdnArray.clone();            for (int i = 0; i < names.length; i++) {                if (names[i] == null) {                    throw new IOException("Cannot create an X500Name");                }            }        }    }     /**     * 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 {        //Note that toDerInputStream uses only the buffer (data) and not        //the tag, so an empty SEQUENCE (OF) will yield an empty DerInputStream        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);    }     /**     * Return an immutable List of all RDNs in this X500Name.     */    public List<RDN> rdns() {        List<RDN> list = rdnList;        if (list == null) {            list = Collections.unmodifiableList(Arrays.asList(names));            rdnList = list;        }        return list;    }     /**     * Return the number of RDNs in this X500Name.     */    public int size() {        return names.length;    }     /**     * Return an immutable List of the the AVAs contained in all the     * RDNs of this X500Name.     */    public List<AVA> allAvas() {        List<AVA> list = allAvaList;        if (list == null) {            list = new ArrayList<AVA>();            for (int i = 0; i < names.length; i++) {                list.addAll(names[i].avas());            }        }        return list;    }     /**     * Return the total number of AVAs contained in all the RDNs of     * this X500Name.     */    public int avaSize() {        return allAvas().size();    }     /**     * Return whether this X500Name is empty. An X500Name is not empty     * if it has at least one RDN containing at least one AVA.     */    public boolean isEmpty() {        int n = names.length;        if (n == 0) {            return true;        }        for (int i = 0; i < n; i++) {            if (names[i].assertion.length != 0) {                return false;            }        }        return true;    }     /**     * Calculates a hash code value for the object.  Objects     * which are equal will also have the same hashcode.     */    public int hashCode() {        return getRFC2253CanonicalName().hashCode();    }     /**     * Compares this name with another, for equality.     *     * @return true iff the names are identical.     */    public boolean equals(Object obj) {        if (this == obj) {            return true;        }        if (obj instanceof X500Name == false) {            return false;        }        X500Name other = (X500Name)obj;        // if we already have the canonical forms, compare now        if ((this.canonicalDn != null) && (other.canonicalDn != null)) {            return this.canonicalDn.equals(other.canonicalDn);        }        // quick check that number of RDNs and AVAs match before canonicalizing        int n = this.names.length;        if (n != other.names.length) {            return false;        }        for (int i = 0; i < n; i++) {            RDN r1 = this.names[i];            RDN r2 = other.names[i];            if (r1.assertion.length != r2.assertion.length) {                return false;            }        }        // definite check via canonical form        String thisCanonical = this.getRFC2253CanonicalName();        String otherCanonical = other.getRFC2253CanonicalName();        return thisCanonical.equals(otherCanonical);    }     /*     * Returns the name component as a Java string, regardless of its     * encoding restrictions.     */    private String getString(DerValue attribute) throws IOException {        if (attribute == null)            return null;        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 "Locality" name component.  If more than one     * such component exists, the topmost one is returned.     *

Lines 1–500 of 1442.