Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/security/auth/x500/X500Principal.java
38918 views
/*1* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.security.auth.x500;2627import java.io.*;28import java.security.Principal;29import java.util.Collections;30import java.util.Map;31import sun.security.x509.X500Name;32import sun.security.util.*;3334/**35* <p> This class represents an X.500 {@code Principal}.36* {@code X500Principal}s are represented by distinguished names such as37* "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US".38*39* <p> This class can be instantiated by using a string representation40* of the distinguished name, or by using the ASN.1 DER encoded byte41* representation of the distinguished name. The current specification42* for the string representation of a distinguished name is defined in43* <a href="http://tools.ietf.org/html/rfc2253">RFC 2253: Lightweight44* Directory Access Protocol (v3): UTF-8 String Representation of45* Distinguished Names</a>. This class, however, accepts string formats from46* both RFC 2253 and <a href="http://tools.ietf.org/html/rfc1779">RFC 1779:47* A String Representation of Distinguished Names</a>, and also recognizes48* attribute type keywords whose OIDs (Object Identifiers) are defined in49* <a href="http://tools.ietf.org/html/rfc5280">RFC 5280: Internet X.50950* Public Key Infrastructure Certificate and CRL Profile</a>.51*52* <p> The string representation for this {@code X500Principal}53* can be obtained by calling the {@code getName} methods.54*55* <p> Note that the {@code getSubjectX500Principal} and56* {@code getIssuerX500Principal} methods of57* {@code X509Certificate} return X500Principals representing the58* issuer and subject fields of the certificate.59*60* @see java.security.cert.X509Certificate61* @since 1.462*/63public final class X500Principal implements Principal, java.io.Serializable {6465private static final long serialVersionUID = -500463348111345721L;6667/**68* RFC 1779 String format of Distinguished Names.69*/70public static final String RFC1779 = "RFC1779";71/**72* RFC 2253 String format of Distinguished Names.73*/74public static final String RFC2253 = "RFC2253";75/**76* Canonical String format of Distinguished Names.77*/78public static final String CANONICAL = "CANONICAL";7980/**81* The X500Name representing this principal.82*83* NOTE: this field is reflectively accessed from within X500Name.84*/85private transient X500Name thisX500Name;8687/**88* Creates an X500Principal by wrapping an X500Name.89*90* NOTE: The constructor is package private. It is intended to be accessed91* using privileged reflection from classes in sun.security.*.92* Currently referenced from sun.security.x509.X500Name.asX500Principal().93*/94X500Principal(X500Name x500Name) {95thisX500Name = x500Name;96}9798/**99* Creates an {@code X500Principal} from a string representation of100* an X.500 distinguished name (ex:101* "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").102* The distinguished name must be specified using the grammar defined in103* RFC 1779 or RFC 2253 (either format is acceptable).104*105* <p>This constructor recognizes the attribute type keywords106* defined in RFC 1779 and RFC 2253107* (and listed in {@link #getName(String format) getName(String format)}),108* as well as the T, DNQ or DNQUALIFIER, SURNAME, GIVENNAME, INITIALS,109* GENERATION, EMAILADDRESS, and SERIALNUMBER keywords whose Object110* Identifiers (OIDs) are defined in RFC 5280.111* Any other attribute type must be specified as an OID.112*113* <p>This implementation enforces a more restrictive OID syntax than114* defined in RFC 1779 and 2253. It uses the more correct syntax defined in115* <a href="http://www.ietf.org/rfc/rfc4512.txt">RFC 4512</a>, which116* specifies that OIDs contain at least 2 digits:117*118* <p>{@code numericoid = number 1*( DOT number ) }119*120* @param name an X.500 distinguished name in RFC 1779 or RFC 2253 format121* @exception NullPointerException if the {@code name}122* is {@code null}123* @exception IllegalArgumentException if the {@code name}124* is improperly specified125*/126public X500Principal(String name) {127this(name, Collections.<String, String>emptyMap());128}129130/**131* Creates an {@code X500Principal} from a string representation of132* an X.500 distinguished name (ex:133* "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").134* The distinguished name must be specified using the grammar defined in135* RFC 1779 or RFC 2253 (either format is acceptable).136*137* <p> This constructor recognizes the attribute type keywords specified138* in {@link #X500Principal(String)} and also recognizes additional139* keywords that have entries in the {@code keywordMap} parameter.140* Keyword entries in the keywordMap take precedence over the default141* keywords recognized by {@code X500Principal(String)}. Keywords142* MUST be specified in all upper-case, otherwise they will be ignored.143* Improperly specified keywords are ignored; however if a keyword in the144* name maps to an improperly specified Object Identifier (OID), an145* {@code IllegalArgumentException} is thrown. It is permissible to146* have 2 different keywords that map to the same OID.147*148* <p>This implementation enforces a more restrictive OID syntax than149* defined in RFC 1779 and 2253. It uses the more correct syntax defined in150* <a href="http://www.ietf.org/rfc/rfc4512.txt">RFC 4512</a>, which151* specifies that OIDs contain at least 2 digits:152*153* <p>{@code numericoid = number 1*( DOT number ) }154*155* @param name an X.500 distinguished name in RFC 1779 or RFC 2253 format156* @param keywordMap an attribute type keyword map, where each key is a157* keyword String that maps to a corresponding object identifier in String158* form (a sequence of nonnegative integers separated by periods). The map159* may be empty but never {@code null}.160* @exception NullPointerException if {@code name} or161* {@code keywordMap} is {@code null}162* @exception IllegalArgumentException if the {@code name} is163* improperly specified or a keyword in the {@code name} maps to an164* OID that is not in the correct form165* @since 1.6166*/167public X500Principal(String name, Map<String, String> keywordMap) {168if (name == null) {169throw new NullPointerException170(sun.security.util.ResourcesMgr.getString171("provided.null.name"));172}173if (keywordMap == null) {174throw new NullPointerException175(sun.security.util.ResourcesMgr.getString176("provided.null.keyword.map"));177}178179try {180thisX500Name = new X500Name(name, keywordMap);181} catch (Exception e) {182IllegalArgumentException iae = new IllegalArgumentException183("improperly specified input name: " + name);184iae.initCause(e);185throw iae;186}187}188189/**190* Creates an {@code X500Principal} from a distinguished name in191* ASN.1 DER encoded form. The ASN.1 notation for this structure is as192* follows.193* <pre>{@code194* Name ::= CHOICE {195* RDNSequence }196*197* RDNSequence ::= SEQUENCE OF RelativeDistinguishedName198*199* RelativeDistinguishedName ::=200* SET SIZE (1 .. MAX) OF AttributeTypeAndValue201*202* AttributeTypeAndValue ::= SEQUENCE {203* type AttributeType,204* value AttributeValue }205*206* AttributeType ::= OBJECT IDENTIFIER207*208* AttributeValue ::= ANY DEFINED BY AttributeType209* ....210* DirectoryString ::= CHOICE {211* teletexString TeletexString (SIZE (1..MAX)),212* printableString PrintableString (SIZE (1..MAX)),213* universalString UniversalString (SIZE (1..MAX)),214* utf8String UTF8String (SIZE (1.. MAX)),215* bmpString BMPString (SIZE (1..MAX)) }216* }</pre>217*218* @param name a byte array containing the distinguished name in ASN.1219* DER encoded form220* @throws IllegalArgumentException if an encoding error occurs221* (incorrect form for DN)222*/223public X500Principal(byte[] name) {224try {225thisX500Name = new X500Name(name);226} catch (Exception e) {227IllegalArgumentException iae = new IllegalArgumentException228("improperly specified input name");229iae.initCause(e);230throw iae;231}232}233234/**235* Creates an {@code X500Principal} from an {@code InputStream}236* containing the distinguished name in ASN.1 DER encoded form.237* The ASN.1 notation for this structure is supplied in the238* documentation for239* {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.240*241* <p> The read position of the input stream is positioned242* to the next available byte after the encoded distinguished name.243*244* @param is an {@code InputStream} containing the distinguished245* name in ASN.1 DER encoded form246*247* @exception NullPointerException if the {@code InputStream}248* is {@code null}249* @exception IllegalArgumentException if an encoding error occurs250* (incorrect form for DN)251*/252public X500Principal(InputStream is) {253if (is == null) {254throw new NullPointerException("provided null input stream");255}256257try {258if (is.markSupported())259is.mark(is.available() + 1);260DerValue der = new DerValue(is);261thisX500Name = new X500Name(der.data);262} catch (Exception e) {263if (is.markSupported()) {264try {265is.reset();266} catch (IOException ioe) {267IllegalArgumentException iae = new IllegalArgumentException268("improperly specified input stream " +269("and unable to reset input stream"));270iae.initCause(e);271throw iae;272}273}274IllegalArgumentException iae = new IllegalArgumentException275("improperly specified input stream");276iae.initCause(e);277throw iae;278}279}280281/**282* Returns a string representation of the X.500 distinguished name using283* the format defined in RFC 2253.284*285* <p>This method is equivalent to calling286* {@code getName(X500Principal.RFC2253)}.287*288* @return the distinguished name of this {@code X500Principal}289*/290public String getName() {291return getName(X500Principal.RFC2253);292}293294/**295* Returns a string representation of the X.500 distinguished name296* using the specified format. Valid values for the format are297* "RFC1779", "RFC2253", and "CANONICAL" (case insensitive).298*299* <p> If "RFC1779" is specified as the format,300* this method emits the attribute type keywords defined in301* RFC 1779 (CN, L, ST, O, OU, C, STREET).302* Any other attribute type is emitted as an OID.303*304* <p> If "RFC2253" is specified as the format,305* this method emits the attribute type keywords defined in306* RFC 2253 (CN, L, ST, O, OU, C, STREET, DC, UID).307* Any other attribute type is emitted as an OID.308* Under a strict reading, RFC 2253 only specifies a UTF-8 string309* representation. The String returned by this method is the310* Unicode string achieved by decoding this UTF-8 representation.311*312* <p> If "CANONICAL" is specified as the format,313* this method returns an RFC 2253 conformant string representation314* with the following additional canonicalizations:315*316* <ol>317* <li> Leading zeros are removed from attribute types318* that are encoded as dotted decimal OIDs319* <li> DirectoryString attribute values of type320* PrintableString and UTF8String are not321* output in hexadecimal format322* <li> DirectoryString attribute values of types323* other than PrintableString and UTF8String324* are output in hexadecimal format325* <li> Leading and trailing white space characters326* are removed from non-hexadecimal attribute values327* (unless the value consists entirely of white space characters)328* <li> Internal substrings of one or more white space characters are329* converted to a single space in non-hexadecimal330* attribute values331* <li> Relative Distinguished Names containing more than one332* Attribute Value Assertion (AVA) are output in the333* following order: an alphabetical ordering of AVAs334* containing standard keywords, followed by a numeric335* ordering of AVAs containing OID keywords.336* <li> The only characters in attribute values that are escaped are337* those which section 2.4 of RFC 2253 states must be escaped338* (they are escaped using a preceding backslash character)339* <li> The entire name is converted to upper case340* using {@code String.toUpperCase(Locale.US)}341* <li> The entire name is converted to lower case342* using {@code String.toLowerCase(Locale.US)}343* <li> The name is finally normalized using normalization form KD,344* as described in the Unicode Standard and UAX #15345* </ol>346*347* <p> Additional standard formats may be introduced in the future.348*349* @param format the format to use350*351* @return a string representation of this {@code X500Principal}352* using the specified format353* @throws IllegalArgumentException if the specified format is invalid354* or null355*/356public String getName(String format) {357if (format != null) {358if (format.equalsIgnoreCase(RFC1779)) {359return thisX500Name.getRFC1779Name();360} else if (format.equalsIgnoreCase(RFC2253)) {361return thisX500Name.getRFC2253Name();362} else if (format.equalsIgnoreCase(CANONICAL)) {363return thisX500Name.getRFC2253CanonicalName();364}365}366throw new IllegalArgumentException("invalid format specified");367}368369/**370* Returns a string representation of the X.500 distinguished name371* using the specified format. Valid values for the format are372* "RFC1779" and "RFC2253" (case insensitive). "CANONICAL" is not373* permitted and an {@code IllegalArgumentException} will be thrown.374*375* <p>This method returns Strings in the format as specified in376* {@link #getName(String)} and also emits additional attribute type377* keywords for OIDs that have entries in the {@code oidMap}378* parameter. OID entries in the oidMap take precedence over the default379* OIDs recognized by {@code getName(String)}.380* Improperly specified OIDs are ignored; however if an OID381* in the name maps to an improperly specified keyword, an382* {@code IllegalArgumentException} is thrown.383*384* <p> Additional standard formats may be introduced in the future.385*386* <p> Warning: additional attribute type keywords may not be recognized387* by other implementations; therefore do not use this method if388* you are unsure if these keywords will be recognized by other389* implementations.390*391* @param format the format to use392* @param oidMap an OID map, where each key is an object identifier in393* String form (a sequence of nonnegative integers separated by periods)394* that maps to a corresponding attribute type keyword String.395* The map may be empty but never {@code null}.396* @return a string representation of this {@code X500Principal}397* using the specified format398* @throws IllegalArgumentException if the specified format is invalid,399* null, or an OID in the name maps to an improperly specified keyword400* @throws NullPointerException if {@code oidMap} is {@code null}401* @since 1.6402*/403public String getName(String format, Map<String, String> oidMap) {404if (oidMap == null) {405throw new NullPointerException406(sun.security.util.ResourcesMgr.getString407("provided.null.OID.map"));408}409if (format != null) {410if (format.equalsIgnoreCase(RFC1779)) {411return thisX500Name.getRFC1779Name(oidMap);412} else if (format.equalsIgnoreCase(RFC2253)) {413return thisX500Name.getRFC2253Name(oidMap);414}415}416throw new IllegalArgumentException("invalid format specified");417}418419/**420* Returns the distinguished name in ASN.1 DER encoded form. The ASN.1421* notation for this structure is supplied in the documentation for422* {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.423*424* <p>Note that the byte array returned is cloned to protect against425* subsequent modifications.426*427* @return a byte array containing the distinguished name in ASN.1 DER428* encoded form429*/430public byte[] getEncoded() {431try {432return thisX500Name.getEncoded();433} catch (IOException e) {434throw new RuntimeException("unable to get encoding", e);435}436}437438/**439* Return a user-friendly string representation of this440* {@code X500Principal}.441*442* @return a string representation of this {@code X500Principal}443*/444public String toString() {445return thisX500Name.toString();446}447448/**449* Compares the specified {@code Object} with this450* {@code X500Principal} for equality.451*452* <p> Specifically, this method returns {@code true} if453* the {@code Object} <i>o</i> is an {@code X500Principal}454* and if the respective canonical string representations455* (obtained via the {@code getName(X500Principal.CANONICAL)} method)456* of this object and <i>o</i> are equal.457*458* <p> This implementation is compliant with the requirements of RFC 5280.459*460* @param o Object to be compared for equality with this461* {@code X500Principal}462*463* @return {@code true} if the specified {@code Object} is equal464* to this {@code X500Principal}, {@code false} otherwise465*/466public boolean equals(Object o) {467if (this == o) {468return true;469}470if (o instanceof X500Principal == false) {471return false;472}473X500Principal other = (X500Principal)o;474return this.thisX500Name.equals(other.thisX500Name);475}476477/**478* Return a hash code for this {@code X500Principal}.479*480* <p> The hash code is calculated via:481* {@code getName(X500Principal.CANONICAL).hashCode()}482*483* @return a hash code for this {@code X500Principal}484*/485public int hashCode() {486return thisX500Name.hashCode();487}488489/**490* Save the X500Principal object to a stream.491*492* @serialData this {@code X500Principal} is serialized493* by writing out its DER-encoded form494* (the value of {@code getEncoded} is serialized).495*/496private void writeObject(java.io.ObjectOutputStream s)497throws IOException {498s.writeObject(thisX500Name.getEncodedInternal());499}500501/**502* Reads this object from a stream (i.e., deserializes it).503*/504private void readObject(java.io.ObjectInputStream s)505throws java.io.IOException,506java.io.NotActiveException,507ClassNotFoundException {508509// re-create thisX500Name510thisX500Name = new X500Name((byte[])s.readObject());511}512}513514515