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