1 /* 2 * Copyright (c) 2007, 2010, 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.ObjectInputStream; 29 import java.io.ObjectOutputStream; 30 import java.io.IOException; 31 import java.util.Collections; 32 import java.util.Date; 33 import java.util.HashMap; 34 import java.util.Map; 35 import java.util.Map.Entry; 36 import javax.security.auth.x500.X500Principal; 37 38 import sun.security.util.ObjectIdentifier; 39 import sun.security.x509.InvalidityDateExtension; 40 41 /** 42 * An exception that indicates an X.509 certificate is revoked. A 43 * <code>CertificateRevokedException</code> contains additional information 44 * about the revoked certificate, such as the date on which the 45 * certificate was revoked and the reason it was revoked. 46 * 47 * @author Sean Mullan 48 * @since 1.7 49 * @see CertPathValidatorException 50 */ 51 public class CertificateRevokedException extends CertificateException { 52 53 private static final long serialVersionUID = 7839996631571608627L; 54 55 /** 56 * @serial the date on which the certificate was revoked 57 */ 58 private Date revocationDate; 59 /** 60 * @serial the revocation reason 61 */ 62 private final CRLReason reason; 63 /** 64 * @serial the <code>X500Principal</code> that represents the name of the 65 * authority that signed the certificate's revocation status information 66 */ 67 private final X500Principal authority; 68 69 private transient Map<String, Extension> extensions; 70 71 /** 72 * Constructs a <code>CertificateRevokedException</code> with 73 * the specified revocation date, reason code, authority name, and map 74 * of extensions. 75 * 76 * @param revocationDate the date on which the certificate was revoked. The 77 * date is copied to protect against subsequent modification. 78 * @param reason the revocation reason 79 * @param extensions a map of X.509 Extensions. Each key is an OID String 80 * that maps to the corresponding Extension. The map is copied to 81 * prevent subsequent modification. 82 * @param authority the <code>X500Principal</code> that represents the name 83 * of the authority that signed the certificate's revocation status 84 * information 85 * @throws NullPointerException if <code>revocationDate</code>, 86 * <code>reason</code>, <code>authority</code>, or 87 * <code>extensions</code> is <code>null</code> 88 */ CertificateRevokedException(Date revocationDate, CRLReason reason, X500Principal authority, Map<String, Extension> extensions)89 public CertificateRevokedException(Date revocationDate, CRLReason reason, 90 X500Principal authority, Map<String, Extension> extensions) { 91 if (revocationDate == null || reason == null || authority == null || 92 extensions == null) { 93 throw new NullPointerException(); 94 } 95 this.revocationDate = new Date(revocationDate.getTime()); 96 this.reason = reason; 97 this.authority = authority; 98 this.extensions = new HashMap(extensions); 99 } 100 101 /** 102 * Returns the date on which the certificate was revoked. A new copy is 103 * returned each time the method is invoked to protect against subsequent 104 * modification. 105 * 106 * @return the revocation date 107 */ getRevocationDate()108 public Date getRevocationDate() { 109 return (Date) revocationDate.clone(); 110 } 111 112 /** 113 * Returns the reason the certificate was revoked. 114 * 115 * @return the revocation reason 116 */ getRevocationReason()117 public CRLReason getRevocationReason() { 118 return reason; 119 } 120 121 /** 122 * Returns the name of the authority that signed the certificate's 123 * revocation status information. 124 * 125 * @return the <code>X500Principal</code> that represents the name of the 126 * authority that signed the certificate's revocation status information 127 */ getAuthorityName()128 public X500Principal getAuthorityName() { 129 return authority; 130 } 131 132 /** 133 * Returns the invalidity date, as specifed in the Invalidity Date 134 * extension of this <code>CertificateRevokedException</code>. The 135 * invalidity date is the date on which it is known or suspected that the 136 * private key was compromised or that the certificate otherwise became 137 * invalid. This implementation calls <code>getExtensions()</code> and 138 * checks the returned map for an entry for the Invalidity Date extension 139 * OID ("2.5.29.24"). If found, it returns the invalidity date in the 140 * extension; otherwise null. A new Date object is returned each time the 141 * method is invoked to protect against subsequent modification. 142 * 143 * @return the invalidity date, or <code>null</code> if not specified 144 */ getInvalidityDate()145 public Date getInvalidityDate() { 146 Extension ext = getExtensions().get("2.5.29.24"); 147 if (ext == null) { 148 return null; 149 } else { 150 try { 151 Date invalidity = 152 (Date) InvalidityDateExtension.toImpl(ext).get("DATE"); 153 return new Date(invalidity.getTime()); 154 } catch (IOException ioe) { 155 return null; 156 } 157 } 158 } 159 160 /** 161 * Returns a map of X.509 extensions containing additional information 162 * about the revoked certificate, such as the Invalidity Date 163 * Extension. Each key is an OID String that maps to the corresponding 164 * Extension. 165 * 166 * @return an unmodifiable map of X.509 extensions, or an empty map 167 * if there are no extensions 168 */ getExtensions()169 public Map<String, Extension> getExtensions() { 170 return Collections.unmodifiableMap(extensions); 171 } 172 173 @Override getMessage()174 public String getMessage() { 175 return "Certificate has been revoked, reason: " 176 + reason + ", revocation date: " + revocationDate 177 + ", authority: " + authority + ", extensions: " + extensions; 178 } 179 180 /** 181 * Serialize this <code>CertificateRevokedException</code> instance. 182 * 183 * @serialData the size of the extensions map (int), followed by all of 184 * the extensions in the map, in no particular order. For each extension, 185 * the following data is emitted: the OID String (Object), the criticality 186 * flag (boolean), the length of the encoded extension value byte array 187 * (int), and the encoded extension value bytes. 188 */ writeObject(ObjectOutputStream oos)189 private void writeObject(ObjectOutputStream oos) throws IOException { 190 // Write out the non-transient fields 191 // (revocationDate, reason, authority) 192 oos.defaultWriteObject(); 193 194 // Write out the size (number of mappings) of the extensions map 195 oos.writeInt(extensions.size()); 196 197 // For each extension in the map, the following are emitted (in order): 198 // the OID String (Object), the criticality flag (boolean), the length 199 // of the encoded extension value byte array (int), and the encoded 200 // extension value byte array. The extensions themselves are emitted 201 // in no particular order. 202 for (Map.Entry<String, Extension> entry : extensions.entrySet()) { 203 Extension ext = entry.getValue(); 204 oos.writeObject(ext.getId()); 205 oos.writeBoolean(ext.isCritical()); 206 byte[] extVal = ext.getValue(); 207 oos.writeInt(extVal.length); 208 oos.write(extVal); 209 } 210 } 211 212 /** 213 * Deserialize the <code>CertificateRevokedException</code> instance. 214 */ readObject(ObjectInputStream ois)215 private void readObject(ObjectInputStream ois) 216 throws IOException, ClassNotFoundException { 217 // Read in the non-transient fields 218 // (revocationDate, reason, authority) 219 ois.defaultReadObject(); 220 221 // Defensively copy the revocation date 222 revocationDate = new Date(revocationDate.getTime()); 223 224 // Read in the size (number of mappings) of the extensions map 225 // and create the extensions map 226 int size = ois.readInt(); 227 if (size == 0) { 228 extensions = Collections.emptyMap(); 229 } else { 230 extensions = new HashMap<String, Extension>(size); 231 } 232 233 // Read in the extensions and put the mappings in the extensions map 234 for (int i = 0; i < size; i++) { 235 String oid = (String) ois.readObject(); 236 boolean critical = ois.readBoolean(); 237 int length = ois.readInt(); 238 byte[] extVal = new byte[length]; 239 ois.readFully(extVal); 240 Extension ext = sun.security.x509.Extension.newExtension 241 (new ObjectIdentifier(oid), critical, extVal); 242 extensions.put(oid, ext); 243 } 244 } 245 } 246