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. encodeThis()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 */ PrivateKeyUsageExtension(Date notBefore, Date notAfter)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 */ PrivateKeyUsageExtension(Boolean critical, Object value)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 */ toString()178 public String toString() { 179 return(super.toString() + 180 "PrivateKeyUsage: [\n" + 181 ((notBefore == null) ? "" : "From: " + notBefore.toString() + ", ") 182 + ((notAfter == null) ? "" : "To: " + notAfter.toString()) 183 + "]\n"); 184 } 185 186 /** 187 * Verify that that the current time is within the validity period. 188 * 189 * @exception CertificateExpiredException if the certificate has expired. 190 * @exception CertificateNotYetValidException if the certificate is not 191 * yet valid. 192 */ valid()193 public void valid() 194 throws CertificateNotYetValidException, CertificateExpiredException { 195 Date now = new Date(); 196 valid(now); 197 } 198 199 /** 200 * Verify that that the passed time is within the validity period. 201 * 202 * @exception CertificateExpiredException if the certificate has expired 203 * with respect to the <code>Date</code> supplied. 204 * @exception CertificateNotYetValidException if the certificate is not 205 * yet valid with respect to the <code>Date</code> supplied. 206 * 207 */ valid(Date now)208 public void valid(Date now) 209 throws CertificateNotYetValidException, CertificateExpiredException { 210 Objects.requireNonNull(now); 211 /* 212 * we use the internal Dates rather than the passed in Date 213 * because someone could override the Date methods after() 214 * and before() to do something entirely different. 215 */ 216 if (notBefore != null && notBefore.after(now)) { 217 throw new CertificateNotYetValidException("NotBefore: " + 218 notBefore.toString()); 219 } 220 if (notAfter != null && notAfter.before(now)) { 221 throw new CertificateExpiredException("NotAfter: " + 222 notAfter.toString()); 223 } 224 } 225 226 /** 227 * Write the extension to the OutputStream. 228 * 229 * @param out the OutputStream to write the extension to. 230 * @exception IOException on encoding errors. 231 */ encode(OutputStream out)232 public void encode(OutputStream out) throws IOException { 233 DerOutputStream tmp = new DerOutputStream(); 234 if (extensionValue == null) { 235 extensionId = PKIXExtensions.PrivateKeyUsage_Id; 236 critical = false; 237 encodeThis(); 238 } 239 super.encode(tmp); 240 out.write(tmp.toByteArray()); 241 } 242 243 /** 244 * Set the attribute value. 245 * @exception CertificateException on attribute handling errors. 246 */ set(String name, Object obj)247 public void set(String name, Object obj) 248 throws CertificateException, IOException { 249 if (!(obj instanceof Date)) { 250 throw new CertificateException("Attribute must be of type Date."); 251 } 252 if (name.equalsIgnoreCase(NOT_BEFORE)) { 253 notBefore = (Date)obj; 254 } else if (name.equalsIgnoreCase(NOT_AFTER)) { 255 notAfter = (Date)obj; 256 } else { 257 throw new CertificateException("Attribute name not recognized by" 258 + " CertAttrSet:PrivateKeyUsage."); 259 } 260 encodeThis(); 261 } 262 263 /** 264 * Get the attribute value. 265 * @exception CertificateException on attribute handling errors. 266 */ get(String name)267 public Date get(String name) throws CertificateException { 268 if (name.equalsIgnoreCase(NOT_BEFORE)) { 269 return (new Date(notBefore.getTime())); 270 } else if (name.equalsIgnoreCase(NOT_AFTER)) { 271 return (new Date(notAfter.getTime())); 272 } else { 273 throw new CertificateException("Attribute name not recognized by" 274 + " CertAttrSet:PrivateKeyUsage."); 275 } 276 } 277 278 /** 279 * Delete the attribute value. 280 * @exception CertificateException on attribute handling errors. 281 */ delete(String name)282 public void delete(String name) throws CertificateException, IOException { 283 if (name.equalsIgnoreCase(NOT_BEFORE)) { 284 notBefore = null; 285 } else if (name.equalsIgnoreCase(NOT_AFTER)) { 286 notAfter = null; 287 } else { 288 throw new CertificateException("Attribute name not recognized by" 289 + " CertAttrSet:PrivateKeyUsage."); 290 } 291 encodeThis(); 292 } 293 294 /** 295 * Return an enumeration of names of attributes existing within this 296 * attribute. 297 */ getElements()298 public Enumeration<String> getElements() { 299 AttributeNameEnumeration elements = new AttributeNameEnumeration(); 300 elements.addElement(NOT_BEFORE); 301 elements.addElement(NOT_AFTER); 302 303 return(elements.elements()); 304 } 305 306 /** 307 * Return the name of this attribute. 308 */ getName()309 public String getName() { 310 return(NAME); 311 } 312 } 313