View Javadoc
1   /*
2    * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package java.security.cert;
27  
28  import java.io.ByteArrayInputStream;
29  import java.io.NotSerializableException;
30  import java.io.ObjectStreamException;
31  import java.io.Serializable;
32  import java.util.Iterator;
33  import java.util.List;
34  
35  /**
36   * An immutable sequence of certificates (a certification path).
37   * <p>
38   * This is an abstract class that defines the methods common to all
39   * {@code CertPath}s. Subclasses can handle different kinds of
40   * certificates (X.509, PGP, etc.).
41   * <p>
42   * All {@code CertPath} objects have a type, a list of
43   * {@code Certificate}s, and one or more supported encodings. Because the
44   * {@code CertPath} class is immutable, a {@code CertPath} cannot
45   * change in any externally visible way after being constructed. This
46   * stipulation applies to all public fields and methods of this class and any
47   * added or overridden by subclasses.
48   * <p>
49   * The type is a {@code String} that identifies the type of
50   * {@code Certificate}s in the certification path. For each
51   * certificate {@code cert} in a certification path {@code certPath},
52   * {@code cert.getType().equals(certPath.getType())} must be
53   * {@code true}.
54   * <p>
55   * The list of {@code Certificate}s is an ordered {@code List} of
56   * zero or more {@code Certificate}s. This {@code List} and all
57   * of the {@code Certificate}s contained in it must be immutable.
58   * <p>
59   * Each {@code CertPath} object must support one or more encodings
60   * so that the object can be translated into a byte array for storage or
61   * transmission to other parties. Preferably, these encodings should be
62   * well-documented standards (such as PKCS#7). One of the encodings supported
63   * by a {@code CertPath} is considered the default encoding. This
64   * encoding is used if no encoding is explicitly requested (for the
65   * {@link #getEncoded() getEncoded()} method, for instance).
66   * <p>
67   * All {@code CertPath} objects are also {@code Serializable}.
68   * {@code CertPath} objects are resolved into an alternate
69   * {@link CertPathRep CertPathRep} object during serialization. This allows
70   * a {@code CertPath} object to be serialized into an equivalent
71   * representation regardless of its underlying implementation.
72   * <p>
73   * {@code CertPath} objects can be created with a
74   * {@code CertificateFactory} or they can be returned by other classes,
75   * such as a {@code CertPathBuilder}.
76   * <p>
77   * By convention, X.509 {@code CertPath}s (consisting of
78   * {@code X509Certificate}s), are ordered starting with the target
79   * certificate and ending with a certificate issued by the trust anchor. That
80   * is, the issuer of one certificate is the subject of the following one. The
81   * certificate representing the {@link TrustAnchor TrustAnchor} should not be
82   * included in the certification path. Unvalidated X.509 {@code CertPath}s
83   * may not follow these conventions. PKIX {@code CertPathValidator}s will
84   * detect any departure from these conventions that cause the certification
85   * path to be invalid and throw a {@code CertPathValidatorException}.
86   *
87   * <p> Every implementation of the Java platform is required to support the
88   * following standard {@code CertPath} encodings:
89   * <ul>
90   * <li>{@code PKCS7}</li>
91   * <li>{@code PkiPath}</li>
92   * </ul>
93   * These encodings are described in the <a href=
94   * "{@docRoot}/../technotes/guides/security/StandardNames.html#CertPathEncodings">
95   * CertPath Encodings section</a> of the
96   * Java Cryptography Architecture Standard Algorithm Name Documentation.
97   * Consult the release documentation for your implementation to see if any
98   * other encodings are supported.
99   * <p>
100  * <b>Concurrent Access</b>
101  * <p>
102  * All {@code CertPath} objects must be thread-safe. That is, multiple
103  * threads may concurrently invoke the methods defined in this class on a
104  * single {@code CertPath} object (or more than one) with no
105  * ill effects. This is also true for the {@code List} returned by
106  * {@code CertPath.getCertificates}.
107  * <p>
108  * Requiring {@code CertPath} objects to be immutable and thread-safe
109  * allows them to be passed around to various pieces of code without worrying
110  * about coordinating access.  Providing this thread-safety is
111  * generally not difficult, since the {@code CertPath} and
112  * {@code List} objects in question are immutable.
113  *
114  * @see CertificateFactory
115  * @see CertPathBuilder
116  *
117  * @author      Yassir Elley
118  * @since       1.4
119  */
120 public abstract class CertPath implements Serializable {
121 
122     private static final long serialVersionUID = 6068470306649138683L;
123 
124     private String type;        // the type of certificates in this chain
125 
126     /**
127      * Creates a {@code CertPath} of the specified type.
128      * <p>
129      * This constructor is protected because most users should use a
130      * {@code CertificateFactory} to create {@code CertPath}s.
131      *
132      * @param type the standard name of the type of
133      * {@code Certificate}s in this path
134      */
135     protected CertPath(String type) {
136         this.type = type;
137     }
138 
139     /**
140      * Returns the type of {@code Certificate}s in this certification
141      * path. This is the same string that would be returned by
142      * {@link java.security.cert.Certificate#getType() cert.getType()}
143      * for all {@code Certificate}s in the certification path.
144      *
145      * @return the type of {@code Certificate}s in this certification
146      * path (never null)
147      */
148     public String getType() {
149         return type;
150     }
151 
152     /**
153      * Returns an iteration of the encodings supported by this certification
154      * path, with the default encoding first. Attempts to modify the returned
155      * {@code Iterator} via its {@code remove} method result in an
156      * {@code UnsupportedOperationException}.
157      *
158      * @return an {@code Iterator} over the names of the supported
159      *         encodings (as Strings)
160      */
161     public abstract Iterator<String> getEncodings();
162 
163     /**
164      * Compares this certification path for equality with the specified
165      * object. Two {@code CertPath}s are equal if and only if their
166      * types are equal and their certificate {@code List}s (and by
167      * implication the {@code Certificate}s in those {@code List}s)
168      * are equal. A {@code CertPath} is never equal to an object that is
169      * not a {@code CertPath}.
170      * <p>
171      * This algorithm is implemented by this method. If it is overridden,
172      * the behavior specified here must be maintained.
173      *
174      * @param other the object to test for equality with this certification path
175      * @return true if the specified object is equal to this certification path,
176      * false otherwise
177      */
178     public boolean equals(Object other) {
179         if (this == other)
180             return true;
181 
182         if (! (other instanceof CertPath))
183             return false;
184 
185         CertPath otherCP = (CertPath) other;
186         if (! otherCP.getType().equals(type))
187             return false;
188 
189         List<? extends Certificate> thisCertList = this.getCertificates();
190         List<? extends Certificate> otherCertList = otherCP.getCertificates();
191         return(thisCertList.equals(otherCertList));
192     }
193 
194     /**
195      * Returns the hashcode for this certification path. The hash code of
196      * a certification path is defined to be the result of the following
197      * calculation:
198      * <pre>{@code
199      *  hashCode = path.getType().hashCode();
200      *  hashCode = 31*hashCode + path.getCertificates().hashCode();
201      * }</pre>
202      * This ensures that {@code path1.equals(path2)} implies that
203      * {@code path1.hashCode()==path2.hashCode()} for any two certification
204      * paths, {@code path1} and {@code path2}, as required by the
205      * general contract of {@code Object.hashCode}.
206      *
207      * @return the hashcode value for this certification path
208      */
209     public int hashCode() {
210         int hashCode = type.hashCode();
211         hashCode = 31*hashCode + getCertificates().hashCode();
212         return hashCode;
213     }
214 
215     /**
216      * Returns a string representation of this certification path.
217      * This calls the {@code toString} method on each of the
218      * {@code Certificate}s in the path.
219      *
220      * @return a string representation of this certification path
221      */
222     public String toString() {
223         StringBuffer sb = new StringBuffer();
224         Iterator<? extends Certificate> stringIterator =
225                                         getCertificates().iterator();
226 
227         sb.append("\n" + type + " Cert Path: length = "
228             + getCertificates().size() + ".\n");
229         sb.append("[\n");
230         int i = 1;
231         while (stringIterator.hasNext()) {
232             sb.append("=========================================="
233                 + "===============Certificate " + i + " start.\n");
234             Certificate stringCert = stringIterator.next();
235             sb.append(stringCert.toString());
236             sb.append("\n========================================"
237                 + "=================Certificate " + i + " end.\n\n\n");
238             i++;
239         }
240 
241         sb.append("\n]");
242         return sb.toString();
243     }
244 
245     /**
246      * Returns the encoded form of this certification path, using the default
247      * encoding.
248      *
249      * @return the encoded bytes
250      * @exception CertificateEncodingException if an encoding error occurs
251      */
252     public abstract byte[] getEncoded()
253         throws CertificateEncodingException;
254 
255     /**
256      * Returns the encoded form of this certification path, using the
257      * specified encoding.
258      *
259      * @param encoding the name of the encoding to use
260      * @return the encoded bytes
261      * @exception CertificateEncodingException if an encoding error occurs or
262      *   the encoding requested is not supported
263      */
264     public abstract byte[] getEncoded(String encoding)
265         throws CertificateEncodingException;
266 
267     /**
268      * Returns the list of certificates in this certification path.
269      * The {@code List} returned must be immutable and thread-safe.
270      *
271      * @return an immutable {@code List} of {@code Certificate}s
272      *         (may be empty, but not null)
273      */
274     public abstract List<? extends Certificate> getCertificates();
275 
276     /**
277      * Replaces the {@code CertPath} to be serialized with a
278      * {@code CertPathRep} object.
279      *
280      * @return the {@code CertPathRep} to be serialized
281      *
282      * @throws ObjectStreamException if a {@code CertPathRep} object
283      * representing this certification path could not be created
284      */
285     protected Object writeReplace() throws ObjectStreamException {
286         try {
287             return new CertPathRep(type, getEncoded());
288         } catch (CertificateException ce) {
289             NotSerializableException nse =
290                 new NotSerializableException
291                     ("java.security.cert.CertPath: " + type);
292             nse.initCause(ce);
293             throw nse;
294         }
295     }
296 
297     /**
298      * Alternate {@code CertPath} class for serialization.
299      * @since 1.4
300      */
301     protected static class CertPathRep implements Serializable {
302 
303         private static final long serialVersionUID = 3015633072427920915L;
304 
305         /** The Certificate type */
306         private String type;
307         /** The encoded form of the cert path */
308         private byte[] data;
309 
310         /**
311          * Creates a {@code CertPathRep} with the specified
312          * type and encoded form of a certification path.
313          *
314          * @param type the standard name of a {@code CertPath} type
315          * @param data the encoded form of the certification path
316          */
317         protected CertPathRep(String type, byte[] data) {
318             this.type = type;
319             this.data = data;
320         }
321 
322         /**
323          * Returns a {@code CertPath} constructed from the type and data.
324          *
325          * @return the resolved {@code CertPath} object
326          *
327          * @throws ObjectStreamException if a {@code CertPath} could not
328          * be constructed
329          */
330         protected Object readResolve() throws ObjectStreamException {
331             try {
332                 CertificateFactory cf = CertificateFactory.getInstance(type);
333                 return cf.generateCertPath(new ByteArrayInputStream(data));
334             } catch (CertificateException ce) {
335                 NotSerializableException nse =
336                     new NotSerializableException
337                         ("java.security.cert.CertPath: " + type);
338                 nse.initCause(ce);
339                 throw nse;
340             }
341         }
342     }
343 }