1 /*
   2  * Copyright (c) 2000, 2011, 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</code>s. Subclasses can handle different kinds of
  40  * certificates (X.509, PGP, etc.).
  41  * <p>
  42  * All <code>CertPath</code> objects have a type, a list of
  43  * <code>Certificate</code>s, and one or more supported encodings. Because the
  44  * <code>CertPath</code> class is immutable, a <code>CertPath</code> 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</code> that identifies the type of
  50  * <code>Certificate</code>s in the certification path. For each
  51  * certificate <code>cert</code> in a certification path <code>certPath</code>,
  52  * <code>cert.getType().equals(certPath.getType())</code> must be
  53  * <code>true</code>.
  54  * <p>
  55  * The list of <code>Certificate</code>s is an ordered <code>List</code> of
  56  * zero or more <code>Certificate</code>s. This <code>List</code> and all
  57  * of the <code>Certificate</code>s contained in it must be immutable.
  58  * <p>
  59  * Each <code>CertPath</code> 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</code> 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</code> objects are also <code>Serializable</code>.
  68  * <code>CertPath</code> objects are resolved into an alternate
  69  * {@link CertPathRep CertPathRep} object during serialization. This allows
  70  * a <code>CertPath</code> object to be serialized into an equivalent
  71  * representation regardless of its underlying implementation.
  72  * <p>
  73  * <code>CertPath</code> objects can be created with a
  74  * <code>CertificateFactory</code> or they can be returned by other classes,
  75  * such as a <code>CertPathBuilder</code>.
  76  * <p>
  77  * By convention, X.509 <code>CertPath</code>s (consisting of
  78  * <code>X509Certificate</code>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</code>s
  83  * may not follow these conventions. PKIX <code>CertPathValidator</code>s will
  84  * detect any departure from these conventions that cause the certification
  85  * path to be invalid and throw a <code>CertPathValidatorException</code>.
  86  *
  87  * <p> Every implementation of the Java platform is required to support the
  88  * following standard <code>CertPath</code> encodings:
  89  * <ul>
  90  * <li><tt>PKCS7</tt></li>
  91  * <li><tt>PkiPath</tt></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</code> 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</code> object (or more than one) with no
 105  * ill effects. This is also true for the <code>List</code> returned by
 106  * <code>CertPath.getCertificates</code>.
 107  * <p>
 108  * Requiring <code>CertPath</code> 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</code> and
 112  * <code>List</code> 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</code> of the specified type.
 128      * <p>
 129      * This constructor is protected because most users should use a
 130      * <code>CertificateFactory</code> to create <code>CertPath</code>s.
 131      *
 132      * @param type the standard name of the type of
 133      * <code>Certificate</code>s in this path
 134      */
 135     protected CertPath(String type) {
 136         this.type = type;
 137     }
 138 
 139     /**
 140      * Returns the type of <code>Certificate</code>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</code>s in the certification path.
 144      *
 145      * @return the type of <code>Certificate</code>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</code> via its <code>remove</code> method result in an
 156      * <code>UnsupportedOperationException</code>.
 157      *
 158      * @return an <code>Iterator</code> 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</code>s are equal if and only if their
 166      * types are equal and their certificate <code>List</code>s (and by
 167      * implication the <code>Certificate</code>s in those <code>List</code>s)
 168      * are equal. A <code>CertPath</code> is never equal to an object that is
 169      * not a <code>CertPath</code>.
 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      * </code></pre>
 202      * This ensures that <code>path1.equals(path2)</code> implies that
 203      * <code>path1.hashCode()==path2.hashCode()</code> for any two certification
 204      * paths, <code>path1</code> and <code>path2</code>, as required by the
 205      * general contract of <code>Object.hashCode</code>.
 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</code> method on each of the
 218      * <code>Certificate</code>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</code> returned must be immutable and thread-safe.
 270      *
 271      * @return an immutable <code>List</code> of <code>Certificate</code>s
 272      *         (may be empty, but not null)
 273      */
 274     public abstract List<? extends Certificate> getCertificates();
 275 
 276     /**
 277      * Replaces the <code>CertPath</code> to be serialized with a
 278      * <code>CertPathRep</code> object.
 279      *
 280      * @return the <code>CertPathRep</code> to be serialized
 281      *
 282      * @throws ObjectStreamException if a <code>CertPathRep</code> 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</code> 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</code> with the specified
 312          * type and encoded form of a certification path.
 313          *
 314          * @param type the standard name of a <code>CertPath</code> 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</code> constructed from the type and data.
 324          *
 325          * @return the resolved <code>CertPath</code> object
 326          *
 327          * @throws ObjectStreamException if a <code>CertPath</code> 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 }