1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.security.cert; 19 20import java.io.ByteArrayInputStream; 21import java.io.NotSerializableException; 22import java.io.ObjectStreamException; 23import java.io.ObjectStreamField; 24import java.io.Serializable; 25import java.util.Iterator; 26import java.util.List; 27 28/** 29 * An immutable certificate path that can be validated. All certificates in the 30 * path are of the same type (i.e., X509). 31 * <p> 32 * A {@code CertPath} can be represented as a byte array in at least one 33 * supported encoding scheme (i.e. PkiPath or PKCS7) when serialized. 34 * <p> 35 * When a {@code List} of the certificates is obtained it must be immutable. 36 * <p> 37 * A {@code CertPath} must be thread-safe without requiring coordinated access. 38 * 39 * @see Certificate 40 */ 41public abstract class CertPath implements Serializable { 42 43 private static final long serialVersionUID = 6068470306649138683L; 44 // Standard name of the type of certificates in this path 45 private final String type; 46 47 /** 48 * Creates a new {@code CertPath} instance for the specified certificate 49 * type. 50 * 51 * @param type 52 * the certificate type. 53 */ 54 protected CertPath(String type) { 55 this.type = type; 56 } 57 58 /** 59 * Returns the type of {@code Certificate} in this instance. 60 * 61 * @return the certificate type. 62 */ 63 public String getType() { 64 return type; 65 } 66 67 /** 68 * Returns {@code true} if {@code Certificate}s in the list are the same 69 * type and the lists are equal (and by implication the certificates 70 * contained within are the same). 71 * 72 * @param other 73 * {@code CertPath} to be compared for equality. 74 * @return {@code true} if the object are equal, {@code false} otherwise. 75 */ 76 public boolean equals(Object other) { 77 if (this == other) { 78 return true; 79 } 80 if (other instanceof CertPath) { 81 CertPath o = (CertPath)other; 82 if (getType().equals(o.getType())) { 83 if (getCertificates().equals(o.getCertificates())) { 84 return true; 85 } 86 } 87 } 88 return false; 89 } 90 91 /** 92 * Overrides {@code Object.hashCode()}. The function is defined as follows: 93 * <pre> 94 * {@code hashCode = 31 * path.getType().hashCode() + 95 * path.getCertificates().hashCode();} 96 * </pre> 97 * 98 * @return the hash code for this instance. 99 */ 100 public int hashCode() { 101 int hash = getType().hashCode(); 102 hash = hash*31 + getCertificates().hashCode(); 103 return hash; 104 } 105 106 /** 107 * Returns a {@code String} representation of this {@code CertPath} 108 * instance. It is the result of calling {@code toString} on all {@code 109 * Certificate}s in the {@code List}. 110 * 111 * @return a string representation of this instance. 112 */ 113 public String toString() { 114 StringBuilder sb = new StringBuilder(getType()); 115 sb.append(" Cert Path, len="); 116 sb.append(getCertificates().size()); 117 sb.append(": [\n"); 118 int n=1; 119 for (Iterator<? extends Certificate> i=getCertificates().iterator(); i.hasNext(); n++) { 120 sb.append("---------------certificate "); 121 sb.append(n); 122 sb.append("---------------\n"); 123 sb.append(((Certificate)i.next()).toString()); 124 } 125 sb.append("\n]"); 126 return sb.toString(); 127 } 128 129 /** 130 * Returns an immutable List of the {@code Certificate}s contained 131 * in the {@code CertPath}. 132 * 133 * @return a list of {@code Certificate}s in the {@code CertPath}. 134 */ 135 public abstract List<? extends Certificate> getCertificates(); 136 137 /** 138 * Returns an encoding of the {@code CertPath} using the default encoding. 139 * 140 * @return default encoding of the {@code CertPath}. 141 * @throws CertificateEncodingException 142 * if the encoding fails. 143 */ 144 public abstract byte[] getEncoded() 145 throws CertificateEncodingException; 146 147 /** 148 * Returns an encoding of this {@code CertPath} using the given 149 * {@code encoding} from {@link #getEncodings()}. 150 * 151 * @throws CertificateEncodingException 152 * if the encoding fails. 153 */ 154 public abstract byte[] getEncoded(String encoding) throws CertificateEncodingException; 155 156 /** 157 * Returns an {@code Iterator} over the supported encodings for a 158 * representation of the certificate path. 159 * 160 * @return {@code Iterator} over supported encodings (as {@code String}s). 161 */ 162 public abstract Iterator<String> getEncodings(); 163 164 /** 165 * Returns an alternate object to be serialized. 166 * 167 * @return an alternate object to be serialized. 168 * @throws ObjectStreamException 169 * if the creation of the alternate object fails. 170 */ 171 protected Object writeReplace() throws ObjectStreamException { 172 try { 173 return new CertPathRep(getType(), getEncoded()); 174 } catch (CertificateEncodingException e) { 175 throw new NotSerializableException("Could not create serialization object: " + e); 176 } 177 } 178 179 /** 180 * The alternate {@code Serializable} class to be used for serialization and 181 * deserialization on {@code CertPath} objects. 182 */ 183 protected static class CertPathRep implements Serializable { 184 185 private static final long serialVersionUID = 3015633072427920915L; 186 // Standard name of the type of certificates in this path 187 private final String type; 188 // cert path data 189 private final byte[] data; 190 191 // Force default serialization to use writeUnshared/readUnshared 192 // for cert path data 193 private static final ObjectStreamField[] serialPersistentFields = { 194 new ObjectStreamField("type", String.class), 195 new ObjectStreamField("data", byte[].class, true), 196 }; 197 198 /** 199 * Creates a new {@code CertPathRep} instance with the specified type 200 * and encoded data. 201 * 202 * @param type 203 * the certificate type. 204 * @param data 205 * the encoded data. 206 */ 207 protected CertPathRep(String type, byte[] data) { 208 this.type = type; 209 this.data = data; 210 } 211 212 /** 213 * Deserializes a {@code CertPath} from a serialized {@code CertPathRep} 214 * object. 215 * 216 * @return the deserialized {@code CertPath}. 217 * @throws ObjectStreamException 218 * if deserialization fails. 219 */ 220 protected Object readResolve() throws ObjectStreamException { 221 try { 222 CertificateFactory cf = CertificateFactory.getInstance(type); 223 return cf.generateCertPath(new ByteArrayInputStream(data)); 224 } catch (Throwable t) { 225 throw new NotSerializableException("Could not resolve cert path: " + t); 226 } 227 } 228 } 229} 230