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 26 package sun.security.x509; 27 28 import java.io.IOException; 29 import java.io.OutputStream; 30 import java.security.cert.CertificateException; 31 import java.security.cert.CertificateParsingException; 32 import java.security.cert.CertificateExpiredException; 33 import java.security.cert.CertificateNotYetValidException; 34 import java.util.Date; 35 import java.util.Enumeration; 36 import java.util.Objects; 37 38 import sun.security.util.*; 39 40 /** 41 * This class defines the Private Key Usage Extension. 42 * 43 * <p>The Private Key Usage Period extension allows the certificate issuer 44 * to specify a different validity period for the private key than the 45 * certificate. This extension is intended for use with digital 46 * signature keys. This extension consists of two optional components 47 * notBefore and notAfter. The private key associated with the 48 * certificate should not be used to sign objects before or after the 49 * times specified by the two components, respectively. 50 * 51 * <pre> 52 * PrivateKeyUsagePeriod ::= SEQUENCE { 53 * notBefore [0] GeneralizedTime OPTIONAL, 54 * notAfter [1] GeneralizedTime OPTIONAL } 55 * </pre> 56 * 57 * @author Amit Kapoor 58 * @author Hemma Prafullchandra 59 * @see Extension 60 * @see CertAttrSet 61 */ 62 public class PrivateKeyUsageExtension extends Extension 63 implements CertAttrSet<String> { 64 /** 65 * Identifier for this attribute, to be used with the 66 * get, set, delete methods of Certificate, x509 type. 67 */ 68 public static final String IDENT = "x509.info.extensions.PrivateKeyUsage"; 69 /** 70 * Sub attributes name for this CertAttrSet. 71 */ 72 public static final String NAME = "PrivateKeyUsage"; 73 public static final String NOT_BEFORE = "not_before"; 74 public static final String NOT_AFTER = "not_after"; 75 76 // Private data members 77 private static final byte TAG_BEFORE = 0; 78 private static final byte TAG_AFTER = 1; 79 80 private Date notBefore = null; 81 private Date notAfter = null; 82 83 // Encode this extension value. 84 private void encodeThis() throws IOException { 85 if (notBefore == null && notAfter == null) { 86 this.extensionValue = null; 87 return; 88 } 89 DerOutputStream seq = new DerOutputStream(); 90 91 DerOutputStream tagged = new DerOutputStream(); 92 if (notBefore != null) { 93 DerOutputStream tmp = new DerOutputStream(); 94 tmp.putGeneralizedTime(notBefore); 95 tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, 96 false, TAG_BEFORE), tmp); 97 } 98 if (notAfter != null) { 99 DerOutputStream tmp = new DerOutputStream(); 100 tmp.putGeneralizedTime(notAfter); 101 tagged.writeImplicit(DerValue.createTag(DerValue.TAG_CONTEXT, 102 false, TAG_AFTER), tmp); 103 } 104 seq.write(DerValue.tag_Sequence, tagged); 105 this.extensionValue = seq.toByteArray(); 106 } 107 108 /** 109 * The default constructor for PrivateKeyUsageExtension. 110 * 111 * @param notBefore the date/time before which the private key 112 * should not be used. 113 * @param notAfter the date/time after which the private key 114 * should not be used. 115 */ 116 public PrivateKeyUsageExtension(Date notBefore, Date notAfter) 117 throws IOException { 118 this.notBefore = notBefore; 119 this.notAfter = notAfter; 120 121 this.extensionId = PKIXExtensions.PrivateKeyUsage_Id; 122 this.critical = false; 123 encodeThis(); 124 } 125 126 /** 127 * Create the extension from the passed DER encoded value. 128 * 129 * @param critical true if the extension is to be treated as critical. 130 * @param value an array of DER encoded bytes of the actual value. 131 * @exception ClassCastException if value is not an array of bytes 132 * @exception CertificateException on certificate parsing errors. 133 * @exception IOException on error. 134 */ 135 public PrivateKeyUsageExtension(Boolean critical, Object value) 136 throws CertificateException, IOException { 137 this.extensionId = PKIXExtensions.PrivateKeyUsage_Id; 138 this.critical = critical.booleanValue(); 139 140 this.extensionValue = (byte[]) value; 141 DerInputStream str = new DerInputStream(this.extensionValue); 142 DerValue[] seq = str.getSequence(2); 143 144 // NB. this is always encoded with the IMPLICIT tag 145 // The checks only make sense if we assume implicit tagging, 146 // with explicit tagging the form is always constructed. 147 for (int i = 0; i < seq.length; i++) { 148 DerValue opt = seq[i]; 149 150 if (opt.isContextSpecific(TAG_BEFORE) && 151 !opt.isConstructed()) { 152 if (notBefore != null) { 153 throw new CertificateParsingException( 154 "Duplicate notBefore in PrivateKeyUsage."); 155 } 156 opt.resetTag(DerValue.tag_GeneralizedTime); 157 str = new DerInputStream(opt.toByteArray()); 158 notBefore = str.getGeneralizedTime(); 159 160 } else if (opt.isContextSpecific(TAG_AFTER) && 161 !opt.isConstructed()) { 162 if (notAfter != null) { 163 throw new CertificateParsingException( 164 "Duplicate notAfter in PrivateKeyUsage."); 165 } 166 opt.resetTag(DerValue.tag_GeneralizedTime); 167 str = new DerInputStream(opt.toByteArray()); 168 notAfter = str.getGeneralizedTime(); 169 } else 170 throw new IOException("Invalid encoding of " + 171 "PrivateKeyUsageExtension"); 172 } 173 } 174 175 /** 176 * Return the printable string. 177 */ 178 public String toString() { 179 StringBuilder sb = new StringBuilder(); 180 sb.append(super.toString()) 181 .append("PrivateKeyUsage: [\n"); 182 if (notBefore != null) { 183 sb.append("From: ") 184 .append(notBefore); 185 if (notAfter != null) { 186 sb.append(", "); 187 } 188 } 189 if (notAfter != null) { 190 sb.append("To: ") 191 .append(notAfter); 192 } 193 sb.append("]\n"); 194 return sb.toString(); 195 } 196 197 /** 198 * Verify that that the current time is within the validity period. 199 * 200 * @exception CertificateExpiredException if the certificate has expired. 201 * @exception CertificateNotYetValidException if the certificate is not 202 * yet valid. 203 */ 204 public void valid() 205 throws CertificateNotYetValidException, CertificateExpiredException { 206 Date now = new Date(); 207 valid(now); 208 } 209 210 /** 211 * Verify that that the passed time is within the validity period. 212 * 213 * @exception CertificateExpiredException if the certificate has expired 214 * with respect to the <code>Date</code> supplied. 215 * @exception CertificateNotYetValidException if the certificate is not 216 * yet valid with respect to the <code>Date</code> supplied. 217 * 218 */ 219 public void valid(Date now) 220 throws CertificateNotYetValidException, CertificateExpiredException { 221 Objects.requireNonNull(now); 222 /* 223 * we use the internal Dates rather than the passed in Date 224 * because someone could override the Date methods after() 225 * and before() to do something entirely different. 226 */ 227 if (notBefore != null && notBefore.after(now)) { 228 throw new CertificateNotYetValidException("NotBefore: " + 229 notBefore.toString()); 230 } 231 if (notAfter != null && notAfter.before(now)) { 232 throw new CertificateExpiredException("NotAfter: " + 233 notAfter.toString()); 234 } 235 } 236 237 /** 238 * Write the extension to the OutputStream. 239 * 240 * @param out the OutputStream to write the extension to. 241 * @exception IOException on encoding errors. 242 */ 243 public void encode(OutputStream out) throws IOException { 244 DerOutputStream tmp = new DerOutputStream(); 245 if (extensionValue == null) { 246 extensionId = PKIXExtensions.PrivateKeyUsage_Id; 247 critical = false; 248 encodeThis(); 249 } 250 super.encode(tmp); 251 out.write(tmp.toByteArray()); 252 } 253 254 /** 255 * Set the attribute value. 256 * @exception CertificateException on attribute handling errors. 257 */ 258 public void set(String name, Object obj) 259 throws CertificateException, IOException { 260 if (!(obj instanceof Date)) { 261 throw new CertificateException("Attribute must be of type Date."); 262 } 263 if (name.equalsIgnoreCase(NOT_BEFORE)) { 264 notBefore = (Date)obj; 265 } else if (name.equalsIgnoreCase(NOT_AFTER)) { 266 notAfter = (Date)obj; 267 } else { 268 throw new CertificateException("Attribute name not recognized by" 269 + " CertAttrSet:PrivateKeyUsage."); 270 } 271 encodeThis(); 272 } 273 274 /** 275 * Get the attribute value. 276 * @exception CertificateException on attribute handling errors. 277 */ 278 public Date get(String name) throws CertificateException { 279 if (name.equalsIgnoreCase(NOT_BEFORE)) { 280 return (new Date(notBefore.getTime())); 281 } else if (name.equalsIgnoreCase(NOT_AFTER)) { 282 return (new Date(notAfter.getTime())); 283 } else { 284 throw new CertificateException("Attribute name not recognized by" 285 + " CertAttrSet:PrivateKeyUsage."); 286 } 287 } 288 289 /** 290 * Delete the attribute value. 291 * @exception CertificateException on attribute handling errors. 292 */ 293 public void delete(String name) throws CertificateException, IOException { 294 if (name.equalsIgnoreCase(NOT_BEFORE)) { 295 notBefore = null; 296 } else if (name.equalsIgnoreCase(NOT_AFTER)) { 297 notAfter = null; 298 } else { 299 throw new CertificateException("Attribute name not recognized by" 300 + " CertAttrSet:PrivateKeyUsage."); 301 } 302 encodeThis(); 303 } 304 305 /** 306 * Return an enumeration of names of attributes existing within this 307 * attribute. 308 */ 309 public Enumeration<String> getElements() { 310 AttributeNameEnumeration elements = new AttributeNameEnumeration(); 311 elements.addElement(NOT_BEFORE); 312 elements.addElement(NOT_AFTER); 313 314 return(elements.elements()); 315 } 316 317 /** 318 * Return the name of this attribute. 319 */ 320 public String getName() { 321 return(NAME); 322 } 323 }