1. /*
  2. * @(#)X500Principal.java 1.19 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.security.auth.x500;
  8. import java.io.*;
  9. import java.security.Principal;
  10. import sun.security.x509.X500Name;
  11. import sun.security.util.*;
  12. /**
  13. * <p> This class represents an X.500 <code>Principal</code>.
  14. * <code>X500Principal</code>s are represented by distinguished names such as
  15. * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US".
  16. *
  17. * <p> This class can be instantiated by using a string representation
  18. * of the distinguished name, or by using the ASN.1 DER encoded byte
  19. * representation of the distinguished name. The current specification
  20. * for the string representation of a distinguished name is defined in
  21. * <a href="http://www.ietf.org/rfc/rfc2253.html">RFC 2253</a>.
  22. * This class, however, accepts string formats from both RFC 2253 and
  23. * <a href="http://www.ietf.org/rfc/rfc1779.html">RFC 1779</a>,
  24. * and also recognizes attribute type keywords whose OIDs
  25. * (Object Identifiers) are defined in
  26. * <a href="http://www.ietf.org/rfc/rfc2459.html">RFC 2459</a>.
  27. *
  28. * <p> The string representation for this <code>X500Principal</code>
  29. * can be obtained by calling the <code>getName</code> methods.
  30. *
  31. * <p> Note that the <code>getSubjectX500Principal</code> and
  32. * <code>getIssuerX500Principal</code> methods of
  33. * <code>X509Certificate</code> return X500Principals representing the
  34. * issuer and subject fields of the certificate.
  35. *
  36. * @version 1.19, 01/23/03
  37. * @see java.security.cert.X509Certificate
  38. * @since 1.4
  39. */
  40. public final class X500Principal implements Principal, java.io.Serializable {
  41. private static final long serialVersionUID = -500463348111345721L;
  42. /**
  43. * RFC 1779 String format of Distinguished Names.
  44. */
  45. public static final String RFC1779 = "RFC1779";
  46. /**
  47. * RFC 2253 String format of Distinguished Names.
  48. */
  49. public static final String RFC2253 = "RFC2253";
  50. /**
  51. * Canonical String format of Distinguished Names.
  52. */
  53. public static final String CANONICAL = "CANONICAL";
  54. /**
  55. * The X500Name representing this principal.
  56. *
  57. * NOTE: this field is reflectively accessed from within X500Name.
  58. */
  59. private transient X500Name thisX500Name;
  60. /**
  61. * Creates an X500Principal by wrapping an X500Name.
  62. *
  63. * NOTE: The constructor is package private. It is intended to be accessed
  64. * using privileged reflection from classes in sun.security.*.
  65. * Currently referenced from sun.security.x509.X500Name.asX500Principal().
  66. */
  67. X500Principal(X500Name x500Name) {
  68. thisX500Name = x500Name;
  69. }
  70. /**
  71. * Creates an <code>X500Principal</code> from a string representation of
  72. * an X.500 distinguished name (ex:
  73. * "CN=Duke, OU=JavaSoft, O=Sun Microsystems, C=US").
  74. * The distinguished name must be specified using the grammar defined in
  75. * RFC 1779 or RFC 2253 (either format is acceptable).
  76. *
  77. * <p>This constructor recognizes the attribute type keywords
  78. * defined in RFC 1779 and RFC 2253
  79. * (and listed in {@link #getName(String format) getName(String format)}),
  80. * as well as the T, DNQ or DNQUALIFIER, SURNAME, GIVENNAME, INITIALS,
  81. * GENERATION, EMAILADDRESS, and SERIALNUMBER keywords whose OIDs are
  82. * defined in RFC 2459 and its successor.
  83. * Any other attribute type must be specified as an OID.
  84. *
  85. * @param name an X.500 distinguished name in RFC 1779 or RFC 2253 format
  86. * @exception NullPointerException if the <code>name</code>
  87. * is <code>null</code>
  88. * @exception IllegalArgumentException if the <code>name</code>
  89. * is improperly specified
  90. */
  91. public X500Principal(String name) {
  92. if (name == null) {
  93. throw new NullPointerException
  94. (sun.security.util.ResourcesMgr.getString
  95. ("provided null name"));
  96. }
  97. try {
  98. thisX500Name = new X500Name(name);
  99. } catch (Exception e) {
  100. IllegalArgumentException iae = new IllegalArgumentException
  101. ("improperly specified input name: " + name);
  102. iae.initCause(e);
  103. throw iae;
  104. }
  105. }
  106. /**
  107. * Creates an <code>X500Principal</code> from a distinguished name in
  108. * ASN.1 DER encoded form. The ASN.1 notation for this structure is as
  109. * follows.
  110. * <pre><code>
  111. * Name ::= CHOICE {
  112. * RDNSequence }
  113. *
  114. * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
  115. *
  116. * RelativeDistinguishedName ::=
  117. * SET SIZE (1 .. MAX) OF AttributeTypeAndValue
  118. *
  119. * AttributeTypeAndValue ::= SEQUENCE {
  120. * type AttributeType,
  121. * value AttributeValue }
  122. *
  123. * AttributeType ::= OBJECT IDENTIFIER
  124. *
  125. * AttributeValue ::= ANY DEFINED BY AttributeType
  126. * ....
  127. * DirectoryString ::= CHOICE {
  128. * teletexString TeletexString (SIZE (1..MAX)),
  129. * printableString PrintableString (SIZE (1..MAX)),
  130. * universalString UniversalString (SIZE (1..MAX)),
  131. * utf8String UTF8String (SIZE (1.. MAX)),
  132. * bmpString BMPString (SIZE (1..MAX)) }
  133. * </code></pre>
  134. *
  135. * @param name a byte array containing the distinguished name in ASN.1
  136. * DER encoded form
  137. * @throws IllegalArgumentException if an encoding error occurs
  138. * (incorrect form for DN)
  139. */
  140. public X500Principal(byte[] name) {
  141. try {
  142. thisX500Name = new X500Name(name);
  143. } catch (Exception e) {
  144. IllegalArgumentException iae = new IllegalArgumentException
  145. ("improperly specified input name");
  146. iae.initCause(e);
  147. throw iae;
  148. }
  149. }
  150. /**
  151. * Creates an <code>X500Principal</code> from an <code>InputStream</code>
  152. * containing the distinguished name in ASN.1 DER encoded form.
  153. * The ASN.1 notation for this structure is supplied in the
  154. * documentation for
  155. * {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.
  156. *
  157. * <p> The read position of the input stream is positioned
  158. * to the next available byte after the encoded distinguished name.
  159. *
  160. * @param is an <code>InputStream</code> containing the distinguished
  161. * name in ASN.1 DER encoded form
  162. *
  163. * @exception NullPointerException if the <code>InputStream</code>
  164. * is <code>null</code>
  165. * @exception IllegalArgumentException if an encoding error occurs
  166. * (incorrect form for DN)
  167. */
  168. public X500Principal(InputStream is) {
  169. if (is == null) {
  170. throw new NullPointerException("provided null input stream");
  171. }
  172. try {
  173. if (is.markSupported())
  174. is.mark(is.available() + 1);
  175. DerValue der = new DerValue(is);
  176. thisX500Name = new X500Name(der.data);
  177. } catch (Exception e) {
  178. if (is.markSupported()) {
  179. try {
  180. is.reset();
  181. } catch (IOException ioe) {
  182. IllegalArgumentException iae = new IllegalArgumentException
  183. ("improperly specified input stream " +
  184. ("and unable to reset input stream"));
  185. iae.initCause(e);
  186. throw iae;
  187. }
  188. }
  189. IllegalArgumentException iae = new IllegalArgumentException
  190. ("improperly specified input stream");
  191. iae.initCause(e);
  192. throw iae;
  193. }
  194. }
  195. /**
  196. * Returns a string representation of the X.500 distinguished name using
  197. * the format defined in RFC 2253.
  198. *
  199. * <p>This method is equivalent to calling
  200. * <code>getName(X500Principal.RFC2253)</code>.
  201. *
  202. * @return the distinguished name of this <code>X500Principal</code>
  203. */
  204. public String getName() {
  205. return getName(X500Principal.RFC2253);
  206. }
  207. /**
  208. * Returns a string representation of the X.500 distinguished name
  209. * using the specified format. Valid values for the format are
  210. * "RFC1779", "RFC2253", and "CANONICAL" (case insensitive).
  211. *
  212. * <p> If "RFC1779" is specified as the format,
  213. * this method emits the attribute type keywords defined in
  214. * RFC 1779 (CN, L, ST, O, OU, C, STREET).
  215. * Any other attribute type is emitted as an OID.
  216. *
  217. * <p> If "RFC2253" is specified as the format,
  218. * this method emits the attribute type keywords defined in
  219. * RFC 2253 (CN, L, ST, O, OU, C, STREET, DC, UID).
  220. * Any other attribute type is emitted as an OID.
  221. * Under a strict reading, RFC 2253 only specifies a UTF-8 string
  222. * representation. The String returned by this method is the
  223. * Unicode string achieved by decoding this UTF-8 representation.
  224. *
  225. * <p> If "CANONICAL" is specified as the format,
  226. * this method returns an RFC 2253 conformant string representation
  227. * with the following additional canonicalizations:
  228. *
  229. * <p><ol>
  230. * <li> Leading zeros are removed from attribute types
  231. * that are encoded as dotted decimal OIDs
  232. * <li> DirectoryString attribute values of type
  233. * PrintableString and UTF8String are not
  234. * output in hexadecimal format
  235. * <li> DirectoryString attribute values of types
  236. * other than PrintableString and UTF8String
  237. * are output in hexadecimal format
  238. * <li> Leading and trailing white space characters
  239. * are removed from non-hexadecimal attribute values
  240. * (unless the value consists entirely of white space characters)
  241. * <li> Internal substrings of one or more white space characters are
  242. * converted to a single space in non-hexadecimal
  243. * attribute values
  244. * <li> Relative Distinguished Names containing more than one
  245. * Attribute Value Assertion (AVA) are output in the
  246. * following order: an alphabetical ordering of AVAs
  247. * containing standard keywords, followed by a numeric
  248. * ordering of AVAs containing OID keywords.
  249. * <li> The only characters in attribute values that are escaped are
  250. * those which section 2.4 of RFC 2253 states must be escaped
  251. * (they are escaped using a preceding backslash character)
  252. * <li> The entire name is converted to upper case
  253. * using <code>String.toUpperCase(Locale.US)</code>
  254. * <li> The entire name is converted to lower case
  255. * using <code>String.toLowerCase(Locale.US)</code>
  256. * <li> The name is finally normalized using normalization form KD,
  257. * as described in the Unicode Standard and UAX #15
  258. * </ol>
  259. *
  260. * <p> Additional standard formats may be introduced in the future.
  261. *
  262. * @param format the format to use
  263. *
  264. * @return a string representation of this <code>X500Principal</code>
  265. * using the specified format
  266. * @throws IllegalArgumentException if the specified format is invalid
  267. */
  268. public String getName(String format) {
  269. if (format != null) {
  270. if (format.equalsIgnoreCase(RFC1779)) {
  271. return thisX500Name.getRFC1779Name();
  272. } else if (format.equalsIgnoreCase(RFC2253)) {
  273. return thisX500Name.getRFC2253Name();
  274. } else if (format.equalsIgnoreCase(CANONICAL)) {
  275. return thisX500Name.getRFC2253CanonicalName();
  276. }
  277. }
  278. throw new IllegalArgumentException("invalid format specified");
  279. }
  280. /**
  281. * Returns the distinguished name in ASN.1 DER encoded form. The ASN.1
  282. * notation for this structure is supplied in the documentation for
  283. * {@link #X500Principal(byte[] name) X500Principal(byte[] name)}.
  284. *
  285. * <p>Note that the byte array returned is cloned to protect against
  286. * subsequent modifications.
  287. *
  288. * @return a byte array containing the distinguished name in ASN.1 DER
  289. * encoded form
  290. */
  291. public byte[] getEncoded() {
  292. try {
  293. return thisX500Name.getEncoded();
  294. } catch (IOException e) {
  295. throw new RuntimeException("unable to get encoding", e);
  296. }
  297. }
  298. /**
  299. * Return a user-friendly string representation of this
  300. * <code>X500Principal</code>.
  301. *
  302. * @return a string representation of this <code>X500Principal</code>
  303. */
  304. public String toString() {
  305. return thisX500Name.toString();
  306. }
  307. /**
  308. * Compares the specified <code>Object</code> with this
  309. * <code>X500Principal</code> for equality.
  310. *
  311. * <p> Specifically, this method returns <code>true</code> if
  312. * the <code>Object</code> <i>o</i> is an <code>X500Principal</code>
  313. * and if the respective canonical string representations
  314. * (obtained via the <code>getName(X500Principal.CANONICAL)</code> method)
  315. * of this object and <i>o</i> are equal.
  316. *
  317. * <p> This implementation is compliant with the requirements of RFC 2459.
  318. *
  319. * @param o Object to be compared for equality with this
  320. * <code>X500Principal</code>
  321. *
  322. * @return <code>true</code> if the specified <code>Object</code> is equal
  323. * to this <code>X500Principal</code>, <code>false</code> otherwise
  324. */
  325. public boolean equals(Object o) {
  326. if (this == o) {
  327. return true;
  328. }
  329. if (o instanceof X500Principal == false) {
  330. return false;
  331. }
  332. X500Principal other = (X500Principal)o;
  333. return this.thisX500Name.equals(other.thisX500Name);
  334. }
  335. /**
  336. * Return a hash code for this <code>X500Principal</code>.
  337. *
  338. * <p> The hash code is calculated via:
  339. * <code>getName(X500Principal.CANONICAL).hashCode()</code>
  340. *
  341. * @return a hash code for this <code>X500Principal</code>
  342. */
  343. public int hashCode() {
  344. return thisX500Name.hashCode();
  345. }
  346. /**
  347. * Save the X500Principal object to a stream.
  348. *
  349. * @serialData this <code>X500Principal</code> is serialized
  350. * by writing out its DER-encoded form
  351. * (the value of <code>getEncoded</code> is serialized).
  352. */
  353. private void writeObject(java.io.ObjectOutputStream s)
  354. throws IOException {
  355. s.writeObject(thisX500Name.getEncodedInternal());
  356. }
  357. /**
  358. * Reads this object from a stream (i.e., deserializes it).
  359. */
  360. private void readObject(java.io.ObjectInputStream s)
  361. throws java.io.IOException,
  362. java.io.NotActiveException,
  363. ClassNotFoundException {
  364. // re-create thisX500Name
  365. thisX500Name = new X500Name((byte[])s.readObject());
  366. }
  367. }