1 /* 2 * Copyright (c) 1997, 2011, 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 package sun.security.x509; 26 27 import java.io.IOException; 28 import java.io.OutputStream; 29 import java.security.cert.*; 30 import java.util.Date; 31 import java.util.Enumeration; 32 33 import sun.security.util.*; 34 35 /** 36 * This class defines the interval for which the certificate is valid. 37 * 38 * @author Amit Kapoor 39 * @author Hemma Prafullchandra 40 * @see CertAttrSet 41 */ 42 public class CertificateValidity implements CertAttrSet<String> { 43 /** 44 * Identifier for this attribute, to be used with the 45 * get, set, delete methods of Certificate, x509 type. 46 */ 47 public static final String IDENT = "x509.info.validity"; 48 /** 49 * Sub attributes name for this CertAttrSet. 50 */ 51 public static final String NAME = "validity"; 52 public static final String NOT_BEFORE = "notBefore"; 53 public static final String NOT_AFTER = "notAfter"; 54 private static final long YR_2050 = 2524636800000L; 55 56 // Private data members 57 private Date notBefore; 58 private Date notAfter; 59 60 // Returns the first time the certificate is valid. getNotBefore()61 private Date getNotBefore() { 62 return (new Date(notBefore.getTime())); 63 } 64 65 // Returns the last time the certificate is valid. getNotAfter()66 private Date getNotAfter() { 67 return (new Date(notAfter.getTime())); 68 } 69 70 // Construct the class from the DerValue construct(DerValue derVal)71 private void construct(DerValue derVal) throws IOException { 72 if (derVal.tag != DerValue.tag_Sequence) { 73 throw new IOException("Invalid encoded CertificateValidity, " + 74 "starting sequence tag missing."); 75 } 76 // check if UTCTime encoded or GeneralizedTime 77 if (derVal.data.available() == 0) 78 throw new IOException("No data encoded for CertificateValidity"); 79 80 DerInputStream derIn = new DerInputStream(derVal.toByteArray()); 81 DerValue[] seq = derIn.getSequence(2); 82 if (seq.length != 2) 83 throw new IOException("Invalid encoding for CertificateValidity"); 84 85 if (seq[0].tag == DerValue.tag_UtcTime) { 86 notBefore = derVal.data.getUTCTime(); 87 } else if (seq[0].tag == DerValue.tag_GeneralizedTime) { 88 notBefore = derVal.data.getGeneralizedTime(); 89 } else { 90 throw new IOException("Invalid encoding for CertificateValidity"); 91 } 92 93 if (seq[1].tag == DerValue.tag_UtcTime) { 94 notAfter = derVal.data.getUTCTime(); 95 } else if (seq[1].tag == DerValue.tag_GeneralizedTime) { 96 notAfter = derVal.data.getGeneralizedTime(); 97 } else { 98 throw new IOException("Invalid encoding for CertificateValidity"); 99 } 100 } 101 102 /** 103 * Default constructor for the class. 104 */ CertificateValidity()105 public CertificateValidity() { } 106 107 /** 108 * The default constructor for this class for the specified interval. 109 * 110 * @param notBefore the date and time before which the certificate 111 * is not valid. 112 * @param notAfter the date and time after which the certificate is 113 * not valid. 114 */ CertificateValidity(Date notBefore, Date notAfter)115 public CertificateValidity(Date notBefore, Date notAfter) { 116 this.notBefore = notBefore; 117 this.notAfter = notAfter; 118 } 119 120 /** 121 * Create the object, decoding the values from the passed DER stream. 122 * 123 * @param in the DerInputStream to read the CertificateValidity from. 124 * @exception IOException on decoding errors. 125 */ CertificateValidity(DerInputStream in)126 public CertificateValidity(DerInputStream in) throws IOException { 127 DerValue derVal = in.getDerValue(); 128 construct(derVal); 129 } 130 131 /** 132 * Return the validity period as user readable string. 133 */ toString()134 public String toString() { 135 if (notBefore == null || notAfter == null) 136 return ""; 137 return ("Validity: [From: " + notBefore.toString() + 138 ",\n To: " + notAfter.toString() + "]"); 139 } 140 141 /** 142 * Encode the CertificateValidity period in DER form to the stream. 143 * 144 * @param out the OutputStream to marshal the contents to. 145 * @exception IOException on errors. 146 */ encode(OutputStream out)147 public void encode(OutputStream out) throws IOException { 148 149 // in cases where default constructor is used check for 150 // null values 151 if (notBefore == null || notAfter == null) { 152 throw new IOException("CertAttrSet:CertificateValidity:" + 153 " null values to encode.\n"); 154 } 155 DerOutputStream pair = new DerOutputStream(); 156 157 if (notBefore.getTime() < YR_2050) { 158 pair.putUTCTime(notBefore); 159 } else 160 pair.putGeneralizedTime(notBefore); 161 162 if (notAfter.getTime() < YR_2050) { 163 pair.putUTCTime(notAfter); 164 } else { 165 pair.putGeneralizedTime(notAfter); 166 } 167 DerOutputStream seq = new DerOutputStream(); 168 seq.write(DerValue.tag_Sequence, pair); 169 170 out.write(seq.toByteArray()); 171 } 172 173 /** 174 * Set the attribute value. 175 */ set(String name, Object obj)176 public void set(String name, Object obj) throws IOException { 177 if (!(obj instanceof Date)) { 178 throw new IOException("Attribute must be of type Date."); 179 } 180 if (name.equalsIgnoreCase(NOT_BEFORE)) { 181 notBefore = (Date)obj; 182 } else if (name.equalsIgnoreCase(NOT_AFTER)) { 183 notAfter = (Date)obj; 184 } else { 185 throw new IOException("Attribute name not recognized by " + 186 "CertAttrSet: CertificateValidity."); 187 } 188 } 189 190 /** 191 * Get the attribute value. 192 */ get(String name)193 public Date get(String name) throws IOException { 194 if (name.equalsIgnoreCase(NOT_BEFORE)) { 195 return (getNotBefore()); 196 } else if (name.equalsIgnoreCase(NOT_AFTER)) { 197 return (getNotAfter()); 198 } else { 199 throw new IOException("Attribute name not recognized by " + 200 "CertAttrSet: CertificateValidity."); 201 } 202 } 203 204 /** 205 * Delete the attribute value. 206 */ delete(String name)207 public void delete(String name) throws IOException { 208 if (name.equalsIgnoreCase(NOT_BEFORE)) { 209 notBefore = null; 210 } else if (name.equalsIgnoreCase(NOT_AFTER)) { 211 notAfter = null; 212 } else { 213 throw new IOException("Attribute name not recognized by " + 214 "CertAttrSet: CertificateValidity."); 215 } 216 } 217 218 /** 219 * Return an enumeration of names of attributes existing within this 220 * attribute. 221 */ getElements()222 public Enumeration<String> getElements() { 223 AttributeNameEnumeration elements = new AttributeNameEnumeration(); 224 elements.addElement(NOT_BEFORE); 225 elements.addElement(NOT_AFTER); 226 227 return (elements.elements()); 228 } 229 230 /** 231 * Return the name of this attribute. 232 */ getName()233 public String getName() { 234 return (NAME); 235 } 236 237 /** 238 * Verify that the current time is within the validity period. 239 * 240 * @exception CertificateExpiredException if the certificate has expired. 241 * @exception CertificateNotYetValidException if the certificate is not 242 * yet valid. 243 */ valid()244 public void valid() 245 throws CertificateNotYetValidException, CertificateExpiredException { 246 Date now = new Date(); 247 valid(now); 248 } 249 250 /** 251 * Verify that the passed time is within the validity period. 252 * @param now the Date against which to compare the validity 253 * period. 254 * 255 * @exception CertificateExpiredException if the certificate has expired 256 * with respect to the <code>Date</code> supplied. 257 * @exception CertificateNotYetValidException if the certificate is not 258 * yet valid with respect to the <code>Date</code> supplied. 259 * 260 */ valid(Date now)261 public void valid(Date now) 262 throws CertificateNotYetValidException, CertificateExpiredException { 263 /* 264 * we use the internal Dates rather than the passed in Date 265 * because someone could override the Date methods after() 266 * and before() to do something entirely different. 267 */ 268 if (notBefore.after(now)) { 269 throw new CertificateNotYetValidException("NotBefore: " + 270 notBefore.toString()); 271 } 272 if (notAfter.before(now)) { 273 throw new CertificateExpiredException("NotAfter: " + 274 notAfter.toString()); 275 } 276 } 277 } 278