package java.security.cert; import java.io.ByteArrayInputStream; import java.io.NotSerializableException; import java.io.ObjectStreamException; import java.io.Serializable; import java.util.Iterator; import java.util.List; import java.util.ListIterator; /** * An immutable sequence of certificates (a certification path).<br /> * <br /> * This is an abstract class that defines the methods common to all * CertPaths. Subclasses can handle different kinds of certificates * (X.509, PGP, etc.).<br /> * <br /> * All CertPath objects have a type, a list of Certificates, and one * or more supported encodings. Because the CertPath class is * immutable, a CertPath cannot change in any externally visible way * after being constructed. This stipulation applies to all public * fields and methods of this class and any added or overridden by * subclasses.<br /> * <br /> * The type is a String that identifies the type of Certificates in * the certification path. For each certificate cert in a * certification path certPath, * cert.getType().equals(certPath.getType()) must be true.<br /> * <br /> * The list of Certificates is an ordered List of zero or more * Certificates. This List and all of the Certificates contained in it * must be immutable.<br /> * <br /> * Each CertPath object must support one or more encodings so that the * object can be translated into a byte array for storage or * transmission to other parties. Preferably, these encodings should * be well-documented standards (such as PKCS#7). One of the encodings * supported by a CertPath is considered the default encoding. This * encoding is used if no encoding is explicitly requested (for the * {@link #getEncoded()} method, for instance).<br /> * <br /> * All CertPath objects are also Serializable. CertPath objects are * resolved into an alternate {@link CertPathRep} object during * serialization. This allows a CertPath object to be serialized into * an equivalent representation regardless of its underlying * implementation.<br /> * <br /> * CertPath objects can be created with a CertificateFactory or they * can be returned by other classes, such as a CertPathBuilder.<br /> * <br /> * By convention, X.509 CertPaths (consisting of X509Certificates), * are ordered starting with the target certificate and ending with a * certificate issued by the trust anchor. That is, the issuer of one * certificate is the subject of the following one. The certificate * representing the {@link TrustAnchor TrustAnchor} should not be included in the * certification path. Unvalidated X.509 CertPaths may not follow * these conventions. PKIX CertPathValidators will detect any * departure from these conventions that cause the certification path * to be invalid and throw a CertPathValidatorException.<br /> * <br /> * <strong>Concurrent Access</strong><br /> * <br /> * All CertPath objects must be thread-safe. That is, multiple threads * may concurrently invoke the methods defined in this class on a * single CertPath object (or more than one) with no ill effects. This * is also true for the List returned by CertPath.getCertificates.<br /> * <br /> * Requiring CertPath objects to be immutable and thread-safe allows * them to be passed around to various pieces of code without worrying * about coordinating access. Providing this thread-safety is * generally not difficult, since the CertPath and List objects in * question are immutable. * * @see CertificateFactory * @see CertPathBuilder */ public abstract class CertPath extends Object implements Serializable { private String type; /** * Alternate <code>CertPath</code> class for serialization. **/ protected static class CertPathRep implements Serializable { private String type; private byte[] data; /** * Creates a <code>CertPathRep</code> with the specified * type and encoded form of a certification path. * * @param type the standard name of a CertPath * @param typedata the encoded form of the certification * path **/ protected CertPathRep(String type, byte[] data) { this.type = type; this.data = data; } /** * Returns a CertPath constructed from the type and data. * * @return the resolved CertPath object * @exception ObjectStreamException if a CertPath could not be constructed **/ protected Object readResolve() throws ObjectStreamException { try { ByteArrayInputStream inStream = new ByteArrayInputStream(data); CertificateFactory cf = CertificateFactory.getInstance(type); return cf.generateCertPath(inStream); } catch ( CertificateException ce ) { throw new NotSerializableException(" java.security.cert.CertPath: " + type); } } } /** * Creates a CertPath of the specified type. * This constructor is protected because most users should use * a CertificateFactory to create CertPaths. * @param type the standard name of the type of Certificatesin this path **/ protected CertPath(String type) { this.type = type; } /** * Returns the type of Certificates in this certification * path. This is the same string that would be returned by * {@link Certificate#getType() cert.getType()} for all * Certificates in the certification path. * * @return the type of Certificates in this certification path (never null) **/ public String getType() { return type; } /** * Returns an iteration of the encodings supported by this * certification path, with the default encoding * first. Attempts to modify the returned Iterator via its * remove method result in an UnsupportedOperationException. * * @return an Iterator over the names of the supported encodings (as Strings) **/ public abstract Iterator getEncodings(); /** * Compares this certification path for equality with the * specified object. Two CertPaths are equal if and only if * their types are equal and their certificate Lists (and by * implication the Certificates in those Lists) are equal. A * CertPath is never equal to an object that is not a * CertPath.<br /> * <br /> * This algorithm is implemented by this method. If it is * overridden, the behavior specified here must be maintained. * * @param other the object to test for equality with this * certification path * * @return true if the specified object is equal to this * certification path, false otherwise * * @see Object#hashCode() Object.hashCode() **/ public boolean equals(Object other) { if (!( other instanceof CertPath ) ) return false; CertPath otherCertPath = (CertPath)other; if ( ! getType().equals(otherCertPath.getType()) ) return false; return getCertificates().equals(otherCertPath.getCertificates()); } /** * Returns the hashcode for this certification path. The hash * code of a certification path is defined to be the result of * the following calculation: * <pre> * hashCode = path.getType().hashCode(); * hashCode = 31 * hashCode + path.getCertificates().hashCode(); * </pre> * This ensures that path1.equals(path2) implies that * path1.hashCode()==path2.hashCode() for any two * certification paths, path1 and path2, as required by the * general contract of Object.hashCode. * * @return The hashcode value for this certification path * * @see #equals(Object) **/ public int hashCode() { return getType().hashCode() * 31 + getCertificates().hashCode(); } /** * Returns a string representation of this certification * path. This calls the toString method on each of the * Certificates in the path. * * @return a string representation of this certification path **/ public String toString() { StringBuffer s = new StringBuffer(); List certs = getCertificates(); ListIterator iter = certs.listIterator(); s.append('\n').append(getType()).append(" Cert Path: length = ").append(certs.size()).append("\n[\n"); while ( iter.hasNext() ) { s.append("=========================================================Certificate ").append(iter.nextIndex()).append('\n'); s.append(iter.next()).append('\n'); s.append("========================================================Certificate end\n\n\n"); } s.append("\n]"); return s.toString(); } /** * Returns the encoded form of this certification path, using * the default encoding. * * @return the encoded bytes * * @exception CertificateEncodingException if an encoding error occurs **/ public abstract byte[] getEncoded() throws CertificateEncodingException; /** * Returns the encoded form of this certification path, using * the specified encoding. * * @param encoding the name of the encoding to use * * @return the encoded bytes * * @exception CertificateEncodingException if an encoding error * occurs or the encoding requested is not supported **/ public abstract byte[] getEncoded(String encoding) throws CertificateEncodingException; /** * Returns the list of certificates in this certification * path. The List returned must be immutable and thread-safe. * * @return an immutable List of Certificates (may be empty, but not null) **/ public abstract List getCertificates(); /** * Replaces the CertPath to be serialized with a CertPathRep * object. * * @return the CertPathRep to be serialized * * @exception ObjectStreamException if a CertPathRep object * representing this certification path could not be created **/ protected Object writeReplace() throws ObjectStreamException { try { return new CertPathRep( getType(), getEncoded() ); } catch ( CertificateException ce ) { throw new NotSerializableException( " java.security.cert.CertPath: " + getType() ); } } }