1. /*
  2. * @(#)CertPath.java 1.9 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.security.cert;
  8. import java.io.ByteArrayInputStream;
  9. import java.io.NotSerializableException;
  10. import java.io.ObjectStreamException;
  11. import java.io.Serializable;
  12. import java.util.Iterator;
  13. import java.util.List;
  14. /**
  15. * An immutable sequence of certificates (a certification path).
  16. * <p>
  17. * This is an abstract class that defines the methods common to all
  18. * <code>CertPath</code>s. Subclasses can handle different kinds of
  19. * certificates (X.509, PGP, etc.).
  20. * <p>
  21. * All <code>CertPath</code> objects have a type, a list of
  22. * <code>Certificate</code>s, and one or more supported encodings. Because the
  23. * <code>CertPath</code> class is immutable, a <code>CertPath</code> cannot
  24. * change in any externally visible way after being constructed. This
  25. * stipulation applies to all public fields and methods of this class and any
  26. * added or overridden by subclasses.
  27. * <p>
  28. * The type is a <code>String</code> that identifies the type of
  29. * <code>Certificate</code>s in the certification path. For each
  30. * certificate <code>cert</code> in a certification path <code>certPath</code>,
  31. * <code>cert.getType().equals(certPath.getType())</code> must be
  32. * <code>true</code>.
  33. * <p>
  34. * The list of <code>Certificate</code>s is an ordered <code>List</code> of
  35. * zero or more <code>Certificate</code>s. This <code>List</code> and all
  36. * of the <code>Certificate</code>s contained in it must be immutable.
  37. * <p>
  38. * Each <code>CertPath</code> object must support one or more encodings
  39. * so that the object can be translated into a byte array for storage or
  40. * transmission to other parties. Preferably, these encodings should be
  41. * well-documented standards (such as PKCS#7). One of the encodings supported
  42. * by a <code>CertPath</code> is considered the default encoding. This
  43. * encoding is used if no encoding is explicitly requested (for the
  44. * {@link #getEncoded() getEncoded()} method, for instance).
  45. * <p>
  46. * All <code>CertPath</code> objects are also <code>Serializable</code>.
  47. * <code>CertPath</code> objects are resolved into an alternate
  48. * {@link CertPathRep CertPathRep} object during serialization. This allows
  49. * a <code>CertPath</code> object to be serialized into an equivalent
  50. * representation regardless of its underlying implementation.
  51. * <p>
  52. * <code>CertPath</code> objects can be created with a
  53. * <code>CertificateFactory</code> or they can be returned by other classes,
  54. * such as a <code>CertPathBuilder</code>.
  55. * <p>
  56. * By convention, X.509 <code>CertPath</code>s (consisting of
  57. * <code>X509Certificate</code>s), are ordered starting with the target
  58. * certificate and ending with a certificate issued by the trust anchor. That
  59. * is, the issuer of one certificate is the subject of the following one. The
  60. * certificate representing the {@link TrustAnchor TrustAnchor} should not be
  61. * included in the certification path. Unvalidated X.509 <code>CertPath</code>s
  62. * may not follow these conventions. PKIX <code>CertPathValidator</code>s will
  63. * detect any departure from these conventions that cause the certification
  64. * path to be invalid and throw a <code>CertPathValidatorException</code>.
  65. * <p>
  66. * <b>Concurrent Access</b>
  67. * <p>
  68. * All <code>CertPath</code> objects must be thread-safe. That is, multiple
  69. * threads may concurrently invoke the methods defined in this class on a
  70. * single <code>CertPath</code> object (or more than one) with no
  71. * ill effects. This is also true for the <code>List</code> returned by
  72. * <code>CertPath.getCertificates</code>.
  73. * <p>
  74. * Requiring <code>CertPath</code> objects to be immutable and thread-safe
  75. * allows them to be passed around to various pieces of code without worrying
  76. * about coordinating access. Providing this thread-safety is
  77. * generally not difficult, since the <code>CertPath</code> and
  78. * <code>List</code> objects in question are immutable.
  79. *
  80. * @see CertificateFactory
  81. * @see CertPathBuilder
  82. *
  83. * @version 1.9 12/19/03
  84. * @author Yassir Elley
  85. * @since 1.4
  86. */
  87. public abstract class CertPath implements Serializable {
  88. private static final long serialVersionUID = 6068470306649138683L;
  89. private String type; // the type of certificates in this chain
  90. /**
  91. * Creates a <code>CertPath</code> of the specified type.
  92. * <p>
  93. * This constructor is protected because most users should use a
  94. * <code>CertificateFactory</code> to create <code>CertPath</code>s.
  95. *
  96. * @param type the standard name of the type of
  97. * <code>Certificate</code>s in this path
  98. */
  99. protected CertPath(String type) {
  100. this.type = type;
  101. }
  102. /**
  103. * Returns the type of <code>Certificate</code>s in this certification
  104. * path. This is the same string that would be returned by
  105. * {@link java.security.cert.Certificate#getType() cert.getType()}
  106. * for all <code>Certificate</code>s in the certification path.
  107. *
  108. * @return the type of <code>Certificate</code>s in this certification
  109. * path (never null)
  110. */
  111. public String getType() {
  112. return type;
  113. }
  114. /**
  115. * Returns an iteration of the encodings supported by this certification
  116. * path, with the default encoding first. Attempts to modify the returned
  117. * <code>Iterator</code> via its <code>remove</code> method result in an
  118. * <code>UnsupportedOperationException</code>.
  119. *
  120. * @return an <code>Iterator</code> over the names of the supported
  121. * encodings (as Strings)
  122. */
  123. public abstract Iterator<String> getEncodings();
  124. /**
  125. * Compares this certification path for equality with the specified
  126. * object. Two <code>CertPath</code>s are equal if and only if their
  127. * types are equal and their certificate <code>List</code>s (and by
  128. * implication the <code>Certificate</code>s in those <code>List</code>s)
  129. * are equal. A <code>CertPath</code> is never equal to an object that is
  130. * not a <code>CertPath</code>.
  131. * <p>
  132. * This algorithm is implemented by this method. If it is overridden,
  133. * the behavior specified here must be maintained.
  134. *
  135. * @param other the object to test for equality with this certification path
  136. * @return true if the specified object is equal to this certification path,
  137. * false otherwise
  138. */
  139. public boolean equals(Object other) {
  140. if (this == other)
  141. return true;
  142. if (! (other instanceof CertPath))
  143. return false;
  144. CertPath otherCP = (CertPath) other;
  145. if (! otherCP.getType().equals(type))
  146. return false;
  147. List thisCertList = this.getCertificates();
  148. List otherCertList = otherCP.getCertificates();
  149. return(thisCertList.equals(otherCertList));
  150. }
  151. /**
  152. * Returns the hashcode for this certification path. The hash code of
  153. * a certification path is defined to be the result of the following
  154. * calculation:
  155. * <pre><code>
  156. * hashCode = path.getType().hashCode();
  157. * hashCode = 31*hashCode + path.getCertificates().hashCode();
  158. * </code></pre>
  159. * This ensures that <code>path1.equals(path2)</code> implies that
  160. * <code>path1.hashCode()==path2.hashCode()</code> for any two certification
  161. * paths, <code>path1</code> and <code>path2</code>, as required by the
  162. * general contract of <code>Object.hashCode</code>.
  163. *
  164. * @return the hashcode value for this certification path
  165. */
  166. public int hashCode() {
  167. int hashCode = type.hashCode();
  168. hashCode = 31*hashCode + getCertificates().hashCode();
  169. return hashCode;
  170. }
  171. /**
  172. * Returns a string representation of this certification path.
  173. * This calls the <code>toString</code> method on each of the
  174. * <code>Certificate</code>s in the path.
  175. *
  176. * @return a string representation of this certification path
  177. */
  178. public String toString() {
  179. StringBuffer sb = new StringBuffer();
  180. Iterator stringIterator = getCertificates().iterator();
  181. sb.append("\n" + type + " Cert Path: length = "
  182. + getCertificates().size() + ".\n");
  183. sb.append("[\n");
  184. int i = 1;
  185. while (stringIterator.hasNext()) {
  186. sb.append("=========================================="
  187. + "===============Certificate " + i + " start.\n");
  188. Certificate stringCert = (Certificate) stringIterator.next();
  189. sb.append(stringCert.toString());
  190. sb.append("\n========================================"
  191. + "=================Certificate " + i + " end.\n\n\n");
  192. i++;
  193. }
  194. sb.append("\n]");
  195. return sb.toString();
  196. }
  197. /**
  198. * Returns the encoded form of this certification path, using the default
  199. * encoding.
  200. *
  201. * @return the encoded bytes
  202. * @exception CertificateEncodingException if an encoding error occurs
  203. */
  204. public abstract byte[] getEncoded()
  205. throws CertificateEncodingException;
  206. /**
  207. * Returns the encoded form of this certification path, using the
  208. * specified encoding.
  209. *
  210. * @param encoding the name of the encoding to use
  211. * @return the encoded bytes
  212. * @exception CertificateEncodingException if an encoding error occurs or
  213. * the encoding requested is not supported
  214. */
  215. public abstract byte[] getEncoded(String encoding)
  216. throws CertificateEncodingException;
  217. /**
  218. * Returns the list of certificates in this certification path.
  219. * The <code>List</code> returned must be immutable and thread-safe.
  220. *
  221. * @return an immutable <code>List</code> of <code>Certificate</code>s
  222. * (may be empty, but not null)
  223. */
  224. public abstract List<? extends Certificate> getCertificates();
  225. /**
  226. * Replaces the <code>CertPath</code> to be serialized with a
  227. * <code>CertPathRep</code> object.
  228. *
  229. * @return the <code>CertPathRep</code> to be serialized
  230. *
  231. * @throws ObjectStreamException if a <code>CertPathRep</code> object
  232. * representing this certification path could not be created
  233. */
  234. protected Object writeReplace() throws ObjectStreamException {
  235. try {
  236. return new CertPathRep(type, getEncoded());
  237. } catch (CertificateException ce) {
  238. NotSerializableException nse =
  239. new NotSerializableException
  240. ("java.security.cert.CertPath: " + type);
  241. nse.initCause(ce);
  242. throw nse;
  243. }
  244. }
  245. /**
  246. * Alternate <code>CertPath</code> class for serialization.
  247. */
  248. protected static class CertPathRep implements Serializable {
  249. private static final long serialVersionUID = 3015633072427920915L;
  250. /** The Certificate type */
  251. private String type;
  252. /** The encoded form of the cert path */
  253. private byte[] data;
  254. /**
  255. * Creates a <code>CertPathRep</code> with the specified
  256. * type and encoded form of a certification path.
  257. *
  258. * @param type the standard name of a <code>CertPath</code> type
  259. * @param data the encoded form of the certification path
  260. */
  261. protected CertPathRep(String type, byte[] data) {
  262. this.type = type;
  263. this.data = data;
  264. }
  265. /**
  266. * Returns a <code>CertPath</code> constructed from the type and data.
  267. *
  268. * @return the resolved <code>CertPath</code> object
  269. *
  270. * @throws ObjectStreamException if a <code>CertPath</code> could not
  271. * be constructed
  272. */
  273. protected Object readResolve() throws ObjectStreamException {
  274. try {
  275. CertificateFactory cf = CertificateFactory.getInstance(type);
  276. return cf.generateCertPath(new ByteArrayInputStream(data));
  277. } catch (CertificateException ce) {
  278. NotSerializableException nse =
  279. new NotSerializableException
  280. ("java.security.cert.CertPath: " + type);
  281. nse.initCause(ce);
  282. throw nse;
  283. }
  284. }
  285. }
  286. }