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 the {@code CertPath} using the specified encoding. 149 * 150 * @param encoding 151 * encoding that should be generated. 152 * @return default encoding of the {@code CertPath}. 153 * @throws CertificateEncodingException 154 * if the encoding fails. 155 */ 156 public abstract byte[] getEncoded(String encoding) 157 throws CertificateEncodingException; 158 159 /** 160 * Returns an {@code Iterator} over the supported encodings for a 161 * representation of the certificate path. 162 * 163 * @return {@code Iterator} over supported encodings (as {@code String}s). 164 */ 165 public abstract Iterator<String> getEncodings(); 166 167 /** 168 * Returns an alternate object to be serialized. 169 * 170 * @return an alternate object to be serialized. 171 * @throws ObjectStreamException 172 * if the creation of the alternate object fails. 173 */ 174 protected Object writeReplace() throws ObjectStreamException { 175 try { 176 return new CertPathRep(getType(), getEncoded()); 177 } catch (CertificateEncodingException e) { 178 throw new NotSerializableException("Could not create serialization object: " + e); 179 } 180 } 181 182 /** 183 * The alternate {@code Serializable} class to be used for serialization and 184 * deserialization on {@code CertPath} objects. 185 */ 186 protected static class CertPathRep implements Serializable { 187 188 private static final long serialVersionUID = 3015633072427920915L; 189 // Standard name of the type of certificates in this path 190 private final String type; 191 // cert path data 192 private final byte[] data; 193 194 // Force default serialization to use writeUnshared/readUnshared 195 // for cert path data 196 private static final ObjectStreamField[] serialPersistentFields = { 197 new ObjectStreamField("type", String.class), 198 new ObjectStreamField("data", byte[].class, true), 199 }; 200 201 /** 202 * Creates a new {@code CertPathRep} instance with the specified type 203 * and encoded data. 204 * 205 * @param type 206 * the certificate type. 207 * @param data 208 * the encoded data. 209 */ 210 protected CertPathRep(String type, byte[] data) { 211 this.type = type; 212 this.data = data; 213 } 214 215 /** 216 * Deserializes a {@code CertPath} from a serialized {@code CertPathRep} 217 * object. 218 * 219 * @return the deserialized {@code CertPath}. 220 * @throws ObjectStreamException 221 * if deserialization fails. 222 */ 223 protected Object readResolve() throws ObjectStreamException { 224 try { 225 CertificateFactory cf = CertificateFactory.getInstance(type); 226 return cf.generateCertPath(new ByteArrayInputStream(data)); 227 } catch (Throwable t) { 228 throw new NotSerializableException("Could not resolve cert path: " + t); 229 } 230 } 231 } 232} 233