001 /*
002 * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.security.cert;
027
028 import java.io.ByteArrayInputStream;
029 import java.io.NotSerializableException;
030 import java.io.ObjectStreamException;
031 import java.io.Serializable;
032 import java.util.Iterator;
033 import java.util.List;
034
035 /**
036 * An immutable sequence of certificates (a certification path).
037 * <p>
038 * This is an abstract class that defines the methods common to all
039 * <code>CertPath</code>s. Subclasses can handle different kinds of
040 * certificates (X.509, PGP, etc.).
041 * <p>
042 * All <code>CertPath</code> objects have a type, a list of
043 * <code>Certificate</code>s, and one or more supported encodings. Because the
044 * <code>CertPath</code> class is immutable, a <code>CertPath</code> cannot
045 * change in any externally visible way after being constructed. This
046 * stipulation applies to all public fields and methods of this class and any
047 * added or overridden by subclasses.
048 * <p>
049 * The type is a <code>String</code> that identifies the type of
050 * <code>Certificate</code>s in the certification path. For each
051 * certificate <code>cert</code> in a certification path <code>certPath</code>,
052 * <code>cert.getType().equals(certPath.getType())</code> must be
053 * <code>true</code>.
054 * <p>
055 * The list of <code>Certificate</code>s is an ordered <code>List</code> of
056 * zero or more <code>Certificate</code>s. This <code>List</code> and all
057 * of the <code>Certificate</code>s contained in it must be immutable.
058 * <p>
059 * Each <code>CertPath</code> object must support one or more encodings
060 * so that the object can be translated into a byte array for storage or
061 * transmission to other parties. Preferably, these encodings should be
062 * well-documented standards (such as PKCS#7). One of the encodings supported
063 * by a <code>CertPath</code> is considered the default encoding. This
064 * encoding is used if no encoding is explicitly requested (for the
065 * {@link #getEncoded() getEncoded()} method, for instance).
066 * <p>
067 * All <code>CertPath</code> objects are also <code>Serializable</code>.
068 * <code>CertPath</code> objects are resolved into an alternate
069 * {@link CertPathRep CertPathRep} object during serialization. This allows
070 * a <code>CertPath</code> object to be serialized into an equivalent
071 * representation regardless of its underlying implementation.
072 * <p>
073 * <code>CertPath</code> objects can be created with a
074 * <code>CertificateFactory</code> or they can be returned by other classes,
075 * such as a <code>CertPathBuilder</code>.
076 * <p>
077 * By convention, X.509 <code>CertPath</code>s (consisting of
078 * <code>X509Certificate</code>s), are ordered starting with the target
079 * certificate and ending with a certificate issued by the trust anchor. That
080 * is, the issuer of one certificate is the subject of the following one. The
081 * certificate representing the {@link TrustAnchor TrustAnchor} should not be
082 * included in the certification path. Unvalidated X.509 <code>CertPath</code>s
083 * may not follow these conventions. PKIX <code>CertPathValidator</code>s will
084 * detect any departure from these conventions that cause the certification
085 * path to be invalid and throw a <code>CertPathValidatorException</code>.
086 * <p>
087 * <b>Concurrent Access</b>
088 * <p>
089 * All <code>CertPath</code> objects must be thread-safe. That is, multiple
090 * threads may concurrently invoke the methods defined in this class on a
091 * single <code>CertPath</code> object (or more than one) with no
092 * ill effects. This is also true for the <code>List</code> returned by
093 * <code>CertPath.getCertificates</code>.
094 * <p>
095 * Requiring <code>CertPath</code> objects to be immutable and thread-safe
096 * allows them to be passed around to various pieces of code without worrying
097 * about coordinating access. Providing this thread-safety is
098 * generally not difficult, since the <code>CertPath</code> and
099 * <code>List</code> objects in question are immutable.
100 *
101 * @see CertificateFactory
102 * @see CertPathBuilder
103 *
104 * @version 1.18 05/05/07
105 * @author Yassir Elley
106 * @since 1.4
107 */
108 public abstract class CertPath implements Serializable {
109
110 private static final long serialVersionUID = 6068470306649138683L;
111
112 private String type; // the type of certificates in this chain
113
114 /**
115 * Creates a <code>CertPath</code> of the specified type.
116 * <p>
117 * This constructor is protected because most users should use a
118 * <code>CertificateFactory</code> to create <code>CertPath</code>s.
119 *
120 * @param type the standard name of the type of
121 * <code>Certificate</code>s in this path
122 */
123 protected CertPath(String type) {
124 this .type = type;
125 }
126
127 /**
128 * Returns the type of <code>Certificate</code>s in this certification
129 * path. This is the same string that would be returned by
130 * {@link java.security.cert.Certificate#getType() cert.getType()}
131 * for all <code>Certificate</code>s in the certification path.
132 *
133 * @return the type of <code>Certificate</code>s in this certification
134 * path (never null)
135 */
136 public String getType() {
137 return type;
138 }
139
140 /**
141 * Returns an iteration of the encodings supported by this certification
142 * path, with the default encoding first. Attempts to modify the returned
143 * <code>Iterator</code> via its <code>remove</code> method result in an
144 * <code>UnsupportedOperationException</code>.
145 *
146 * @return an <code>Iterator</code> over the names of the supported
147 * encodings (as Strings)
148 */
149 public abstract Iterator<String> getEncodings();
150
151 /**
152 * Compares this certification path for equality with the specified
153 * object. Two <code>CertPath</code>s are equal if and only if their
154 * types are equal and their certificate <code>List</code>s (and by
155 * implication the <code>Certificate</code>s in those <code>List</code>s)
156 * are equal. A <code>CertPath</code> is never equal to an object that is
157 * not a <code>CertPath</code>.
158 * <p>
159 * This algorithm is implemented by this method. If it is overridden,
160 * the behavior specified here must be maintained.
161 *
162 * @param other the object to test for equality with this certification path
163 * @return true if the specified object is equal to this certification path,
164 * false otherwise
165 */
166 public boolean equals(Object other) {
167 if (this == other)
168 return true;
169
170 if (!(other instanceof CertPath))
171 return false;
172
173 CertPath otherCP = (CertPath) other;
174 if (!otherCP.getType().equals(type))
175 return false;
176
177 List<? extends Certificate> this CertList = this
178 .getCertificates();
179 List<? extends Certificate> otherCertList = otherCP
180 .getCertificates();
181 return (this CertList.equals(otherCertList));
182 }
183
184 /**
185 * Returns the hashcode for this certification path. The hash code of
186 * a certification path is defined to be the result of the following
187 * calculation:
188 * <pre><code>
189 * hashCode = path.getType().hashCode();
190 * hashCode = 31*hashCode + path.getCertificates().hashCode();
191 * </code></pre>
192 * This ensures that <code>path1.equals(path2)</code> implies that
193 * <code>path1.hashCode()==path2.hashCode()</code> for any two certification
194 * paths, <code>path1</code> and <code>path2</code>, as required by the
195 * general contract of <code>Object.hashCode</code>.
196 *
197 * @return the hashcode value for this certification path
198 */
199 public int hashCode() {
200 int hashCode = type.hashCode();
201 hashCode = 31 * hashCode + getCertificates().hashCode();
202 return hashCode;
203 }
204
205 /**
206 * Returns a string representation of this certification path.
207 * This calls the <code>toString</code> method on each of the
208 * <code>Certificate</code>s in the path.
209 *
210 * @return a string representation of this certification path
211 */
212 public String toString() {
213 StringBuffer sb = new StringBuffer();
214 Iterator<? extends Certificate> stringIterator = getCertificates()
215 .iterator();
216
217 sb.append("\n" + type + " Cert Path: length = "
218 + getCertificates().size() + ".\n");
219 sb.append("[\n");
220 int i = 1;
221 while (stringIterator.hasNext()) {
222 sb.append("=========================================="
223 + "===============Certificate " + i + " start.\n");
224 Certificate stringCert = stringIterator.next();
225 sb.append(stringCert.toString());
226 sb.append("\n========================================"
227 + "=================Certificate " + i
228 + " end.\n\n\n");
229 i++;
230 }
231
232 sb.append("\n]");
233 return sb.toString();
234 }
235
236 /**
237 * Returns the encoded form of this certification path, using the default
238 * encoding.
239 *
240 * @return the encoded bytes
241 * @exception CertificateEncodingException if an encoding error occurs
242 */
243 public abstract byte[] getEncoded()
244 throws CertificateEncodingException;
245
246 /**
247 * Returns the encoded form of this certification path, using the
248 * specified encoding.
249 *
250 * @param encoding the name of the encoding to use
251 * @return the encoded bytes
252 * @exception CertificateEncodingException if an encoding error occurs or
253 * the encoding requested is not supported
254 */
255 public abstract byte[] getEncoded(String encoding)
256 throws CertificateEncodingException;
257
258 /**
259 * Returns the list of certificates in this certification path.
260 * The <code>List</code> returned must be immutable and thread-safe.
261 *
262 * @return an immutable <code>List</code> of <code>Certificate</code>s
263 * (may be empty, but not null)
264 */
265 public abstract List<? extends Certificate> getCertificates();
266
267 /**
268 * Replaces the <code>CertPath</code> to be serialized with a
269 * <code>CertPathRep</code> object.
270 *
271 * @return the <code>CertPathRep</code> to be serialized
272 *
273 * @throws ObjectStreamException if a <code>CertPathRep</code> object
274 * representing this certification path could not be created
275 */
276 protected Object writeReplace() throws ObjectStreamException {
277 try {
278 return new CertPathRep(type, getEncoded());
279 } catch (CertificateException ce) {
280 NotSerializableException nse = new NotSerializableException(
281 "java.security.cert.CertPath: " + type);
282 nse.initCause(ce);
283 throw nse;
284 }
285 }
286
287 /**
288 * Alternate <code>CertPath</code> class for serialization.
289 * @since 1.4
290 */
291 protected static class CertPathRep implements Serializable {
292
293 private static final long serialVersionUID = 3015633072427920915L;
294
295 /** The Certificate type */
296 private String type;
297 /** The encoded form of the cert path */
298 private byte[] data;
299
300 /**
301 * Creates a <code>CertPathRep</code> with the specified
302 * type and encoded form of a certification path.
303 *
304 * @param type the standard name of a <code>CertPath</code> type
305 * @param data the encoded form of the certification path
306 */
307 protected CertPathRep(String type, byte[] data) {
308 this .type = type;
309 this .data = data;
310 }
311
312 /**
313 * Returns a <code>CertPath</code> constructed from the type and data.
314 *
315 * @return the resolved <code>CertPath</code> object
316 *
317 * @throws ObjectStreamException if a <code>CertPath</code> could not
318 * be constructed
319 */
320 protected Object readResolve() throws ObjectStreamException {
321 try {
322 CertificateFactory cf = CertificateFactory
323 .getInstance(type);
324 return cf.generateCertPath(new ByteArrayInputStream(
325 data));
326 } catch (CertificateException ce) {
327 NotSerializableException nse = new NotSerializableException(
328 "java.security.cert.CertPath: " + type);
329 nse.initCause(ce);
330 throw nse;
331 }
332 }
333 }
334 }
|