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