1 /*
   2  * Copyright (c) 2000, 2019, 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}/../specs/security/standard-names.html#certpath-encodings">
  95  * CertPath Encodings section</a> of the
  96  * Java Security Standard Algorithm Names Specification.
  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     @java.io.Serial
 123     private static final long serialVersionUID = 6068470306649138683L;
 124 
 125     private String type;        // the type of certificates in this chain
 126 
 127     /**
 128      * Creates a {@code CertPath} of the specified type.
 129      * <p>
 130      * This constructor is protected because most users should use a
 131      * {@code CertificateFactory} to create {@code CertPath}s.
 132      *
 133      * @param type the standard name of the type of
 134      * {@code Certificate}s in this path
 135      */
 136     protected CertPath(String type) {
 137         this.type = type;
 138     }
 139 
 140     /**
 141      * Returns the type of {@code Certificate}s in this certification
 142      * path. This is the same string that would be returned by
 143      * {@link java.security.cert.Certificate#getType() cert.getType()}
 144      * for all {@code Certificate}s in the certification path.
 145      *
 146      * @return the type of {@code Certificate}s in this certification
 147      * path (never null)
 148      */
 149     public String getType() {
 150         return type;
 151     }
 152 
 153     /**
 154      * Returns an iteration of the encodings supported by this certification
 155      * path, with the default encoding first. Attempts to modify the returned
 156      * {@code Iterator} via its {@code remove} method result in an
 157      * {@code UnsupportedOperationException}.
 158      *
 159      * @return an {@code Iterator} over the names of the supported
 160      *         encodings (as Strings)
 161      */
 162     public abstract Iterator<String> getEncodings();
 163 
 164     /**
 165      * Compares this certification path for equality with the specified
 166      * object. Two {@code CertPath}s are equal if and only if their
 167      * types are equal and their certificate {@code List}s (and by
 168      * implication the {@code Certificate}s in those {@code List}s)
 169      * are equal. A {@code CertPath} is never equal to an object that is
 170      * not a {@code CertPath}.
 171      * <p>
 172      * This algorithm is implemented by this method. If it is overridden,
 173      * the behavior specified here must be maintained.
 174      *
 175      * @param other the object to test for equality with this certification path
 176      * @return true if the specified object is equal to this certification path,
 177      * false otherwise
 178      */
 179     public boolean equals(Object other) {
 180         if (this == other)
 181             return true;
 182 
 183         if (! (other instanceof CertPath))
 184             return false;
 185 
 186         CertPath otherCP = (CertPath) other;
 187         if (! otherCP.getType().equals(type))
 188             return false;
 189 
 190         List<? extends Certificate> thisCertList = this.getCertificates();
 191         List<? extends Certificate> otherCertList = otherCP.getCertificates();
 192         return(thisCertList.equals(otherCertList));
 193     }
 194 
 195     /**
 196      * Returns the hashcode for this certification path. The hash code of
 197      * a certification path is defined to be the result of the following
 198      * calculation:
 199      * <pre>{@code
 200      *  hashCode = path.getType().hashCode();
 201      *  hashCode = 31*hashCode + path.getCertificates().hashCode();
 202      * }</pre>
 203      * This ensures that {@code path1.equals(path2)} implies that
 204      * {@code path1.hashCode()==path2.hashCode()} for any two certification
 205      * paths, {@code path1} and {@code path2}, as required by the
 206      * general contract of {@code Object.hashCode}.
 207      *
 208      * @return the hashcode value for this certification path
 209      */
 210     public int hashCode() {
 211         int hashCode = type.hashCode();
 212         hashCode = 31*hashCode + getCertificates().hashCode();
 213         return hashCode;
 214     }
 215 
 216     /**
 217      * Returns a string representation of this certification path.
 218      * This calls the {@code toString} method on each of the
 219      * {@code Certificate}s in the path.
 220      *
 221      * @return a string representation of this certification path
 222      */
 223     public String toString() {
 224         StringBuilder sb = new StringBuilder();
 225         Iterator<? extends Certificate> stringIterator =
 226                                         getCertificates().iterator();
 227 
 228         sb.append("\n" + type + " Cert Path: length = "
 229             + getCertificates().size() + ".\n");
 230         sb.append("[\n");
 231         int i = 1;
 232         while (stringIterator.hasNext()) {
 233             sb.append("=========================================="
 234                 + "===============Certificate " + i + " start.\n");
 235             Certificate stringCert = stringIterator.next();
 236             sb.append(stringCert.toString());
 237             sb.append("\n========================================"
 238                 + "=================Certificate " + i + " end.\n\n\n");
 239             i++;
 240         }
 241 
 242         sb.append("\n]");
 243         return sb.toString();
 244     }
 245 
 246     /**
 247      * Returns the encoded form of this certification path, using the default
 248      * encoding.
 249      *
 250      * @return the encoded bytes
 251      * @throws    CertificateEncodingException if an encoding error occurs
 252      */
 253     public abstract byte[] getEncoded()
 254         throws CertificateEncodingException;
 255 
 256     /**
 257      * Returns the encoded form of this certification path, using the
 258      * specified encoding.
 259      *
 260      * @param encoding the name of the encoding to use
 261      * @return the encoded bytes
 262      * @throws    CertificateEncodingException if an encoding error occurs or
 263      *   the encoding requested is not supported
 264      */
 265     public abstract byte[] getEncoded(String encoding)
 266         throws CertificateEncodingException;
 267 
 268     /**
 269      * Returns the list of certificates in this certification path.
 270      * The {@code List} returned must be immutable and thread-safe.
 271      *
 272      * @return an immutable {@code List} of {@code Certificate}s
 273      *         (may be empty, but not null)
 274      */
 275     public abstract List<? extends Certificate> getCertificates();
 276 
 277     /**
 278      * Replaces the {@code CertPath} to be serialized with a
 279      * {@code CertPathRep} object.
 280      *
 281      * @return the {@code CertPathRep} to be serialized
 282      *
 283      * @throws ObjectStreamException if a {@code CertPathRep} object
 284      * representing this certification path could not be created
 285      */
 286     @java.io.Serial
 287     protected Object writeReplace() throws ObjectStreamException {
 288         try {
 289             return new CertPathRep(type, getEncoded());
 290         } catch (CertificateException ce) {
 291             NotSerializableException nse =
 292                 new NotSerializableException
 293                     ("java.security.cert.CertPath: " + type);
 294             nse.initCause(ce);
 295             throw nse;
 296         }
 297     }
 298 
 299     /**
 300      * Alternate {@code CertPath} class for serialization.
 301      * @since 1.4
 302      */
 303     protected static class CertPathRep implements Serializable {
 304 
 305         @java.io.Serial
 306         private static final long serialVersionUID = 3015633072427920915L;
 307 
 308         /** The Certificate type */
 309         private String type;
 310         /** The encoded form of the cert path */
 311         private byte[] data;
 312 
 313         /**
 314          * Creates a {@code CertPathRep} with the specified
 315          * type and encoded form of a certification path.
 316          *
 317          * @param type the standard name of a {@code CertPath} type
 318          * @param data the encoded form of the certification path
 319          */
 320         protected CertPathRep(String type, byte[] data) {
 321             this.type = type;
 322             this.data = data;
 323         }
 324 
 325         /**
 326          * Returns a {@code CertPath} constructed from the type and data.
 327          *
 328          * @return the resolved {@code CertPath} object
 329          *
 330          * @throws ObjectStreamException if a {@code CertPath} could not
 331          * be constructed
 332          */
 333         @java.io.Serial
 334         protected Object readResolve() throws ObjectStreamException {
 335             try {
 336                 CertificateFactory cf = CertificateFactory.getInstance(type);
 337                 return cf.generateCertPath(new ByteArrayInputStream(data));
 338             } catch (CertificateException ce) {
 339                 NotSerializableException nse =
 340                     new NotSerializableException
 341                         ("java.security.cert.CertPath: " + type);
 342                 nse.initCause(ce);
 343                 throw nse;
 344             }
 345         }
 346     }
 347 }