001: /*
002: * @(#)PrivateKeyUsageExtension.java 1.24 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package sun.security.x509;
029:
030: import java.io.IOException;
031: import java.io.InputStream;
032: import java.io.OutputStream;
033: import java.lang.reflect.Array;
034: import java.security.cert.CertificateException;
035: import java.security.cert.CertificateParsingException;
036: import java.security.cert.CertificateExpiredException;
037: import java.security.cert.CertificateNotYetValidException;
038: import java.util.Date;
039: import java.util.Enumeration;
040:
041: import sun.security.util.*;
042:
043: /**
044: * This class defines the Private Key Usage Extension.
045: *
046: * <p>The Private Key Usage Period extension allows the certificate issuer
047: * to specify a different validity period for the private key than the
048: * certificate. This extension is intended for use with digital
049: * signature keys. This extension consists of two optional components
050: * notBefore and notAfter. The private key associated with the
051: * certificate should not be used to sign objects before or after the
052: * times specified by the two components, respectively.
053: *
054: * <pre>
055: * PrivateKeyUsagePeriod ::= SEQUENCE {
056: * notBefore [0] GeneralizedTime OPTIONAL,
057: * notAfter [1] GeneralizedTime OPTIONAL }
058: * </pre>
059: *
060: * @author Amit Kapoor
061: * @author Hemma Prafullchandra
062: * @version 1.17
063: * @see Extension
064: * @see CertAttrSet
065: */
066: public class PrivateKeyUsageExtension extends Extension implements
067: CertAttrSet {
068: /**
069: * Identifier for this attribute, to be used with the
070: * get, set, delete methods of Certificate, x509 type.
071: */
072: public static final String IDENT = "x509.info.extensions.PrivateKeyUsage";
073: /**
074: * Sub attributes name for this CertAttrSet.
075: */
076: public static final String NAME = "PrivateKeyUsage";
077: public static final String NOT_BEFORE = "not_before";
078: public static final String NOT_AFTER = "not_after";
079:
080: // Private data members
081: private static final byte TAG_BEFORE = 0;
082: private static final byte TAG_AFTER = 1;
083:
084: private Date notBefore = null;
085: private Date notAfter = null;
086:
087: // Encode this extension value.
088: private void encodeThis() throws IOException {
089: if (notBefore == null && notAfter == null) {
090: this .extensionValue = null;
091: return;
092: }
093: DerOutputStream seq = new DerOutputStream();
094:
095: DerOutputStream tagged = new DerOutputStream();
096: if (notBefore != null) {
097: DerOutputStream tmp = new DerOutputStream();
098: tmp.putGeneralizedTime(notBefore);
099: tagged.writeImplicit(DerValue.createTag(
100: DerValue.TAG_CONTEXT, false, TAG_BEFORE), tmp);
101: }
102: if (notAfter != null) {
103: DerOutputStream tmp = new DerOutputStream();
104: tmp.putGeneralizedTime(notAfter);
105: tagged.writeImplicit(DerValue.createTag(
106: DerValue.TAG_CONTEXT, false, TAG_AFTER), tmp);
107: }
108: seq.write(DerValue.tag_Sequence, tagged);
109: this .extensionValue = seq.toByteArray();
110: }
111:
112: /**
113: * The default constructor for PrivateKeyUsageExtension.
114: *
115: * @param notBefore the date/time before which the private key
116: * should not be used.
117: * @param notAfter the date/time after which the private key
118: * should not be used.
119: */
120: public PrivateKeyUsageExtension(Date notBefore, Date notAfter)
121: throws IOException {
122: this .notBefore = notBefore;
123: this .notAfter = notAfter;
124:
125: this .extensionId = PKIXExtensions.PrivateKeyUsage_Id;
126: this .critical = false;
127: encodeThis();
128: }
129:
130: /**
131: * Create the extension from the passed DER encoded value.
132: *
133: * @param critical true if the extension is to be treated as critical.
134: * @param value Array of DER encoded bytes of the actual value.
135: *
136: * @exception CertificateException on certificate parsing errors.
137: * @exception IOException on error.
138: */
139: public PrivateKeyUsageExtension(Boolean critical, Object value)
140: throws CertificateException, IOException {
141: this .extensionId = PKIXExtensions.PrivateKeyUsage_Id;
142: this .critical = critical.booleanValue();
143:
144: if (!(value instanceof byte[]))
145: throw new CertificateException("Illegal argument type");
146:
147: int len = Array.getLength(value);
148: byte[] extValue = new byte[len];
149: System.arraycopy(value, 0, extValue, 0, len);
150:
151: this .extensionValue = extValue;
152: DerInputStream str = new DerInputStream(extValue);
153: DerValue[] seq = str.getSequence(2);
154:
155: // NB. this is always encoded with the IMPLICIT tag
156: // The checks only make sense if we assume implicit tagging,
157: // with explicit tagging the form is always constructed.
158: for (int i = 0; i < seq.length; i++) {
159: DerValue opt = seq[i];
160:
161: if (opt.isContextSpecific((byte) TAG_BEFORE)
162: && !opt.isConstructed()) {
163: if (notBefore != null) {
164: throw new CertificateParsingException(
165: "Duplicate notBefore in PrivateKeyUsage.");
166: }
167: opt.resetTag(DerValue.tag_GeneralizedTime);
168: str = new DerInputStream(opt.toByteArray());
169: notBefore = str.getGeneralizedTime();
170:
171: } else if (opt.isContextSpecific((byte) TAG_AFTER)
172: && !opt.isConstructed()) {
173: if (notAfter != null) {
174: throw new CertificateParsingException(
175: "Duplicate notAfter in PrivateKeyUsage.");
176: }
177: opt.resetTag(DerValue.tag_GeneralizedTime);
178: str = new DerInputStream(opt.toByteArray());
179: notAfter = str.getGeneralizedTime();
180: } else
181: throw new IOException("Invalid encoding of "
182: + "PrivateKeyUsageExtension");
183: }
184: }
185:
186: /**
187: * Return the printable string.
188: */
189: public String toString() {
190: return (super .toString()
191: + "PrivateKeyUsage: [\n"
192: + ((notBefore == null) ? "" : "From: "
193: + notBefore.toString() + ", ")
194: + ((notAfter == null) ? "" : "To: "
195: + notAfter.toString()) + "]\n");
196: }
197:
198: /**
199: * Verify that that the current time is within the validity period.
200: *
201: * @exception CertificateExpiredException if the certificate has expired.
202: * @exception CertificateNotYetValidException if the certificate is not
203: * yet valid.
204: */
205: public void valid() throws CertificateNotYetValidException,
206: CertificateExpiredException {
207: Date now = new Date();
208: valid(now);
209: }
210:
211: /**
212: * Verify that that the passed time is within the validity period.
213: *
214: * @exception CertificateExpiredException if the certificate has expired
215: * with respect to the <code>Date</code> supplied.
216: * @exception CertificateNotYetValidException if the certificate is not
217: * yet valid with respect to the <code>Date</code> supplied.
218: *
219: */
220: public void valid(Date now) throws CertificateNotYetValidException,
221: CertificateExpiredException {
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.after(now)) {
228: throw new CertificateNotYetValidException("NotBefore: "
229: + notBefore.toString());
230: }
231: if (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: * Decode the extension from the InputStream.
256: *
257: * @param in the InputStream to unmarshal the contents from.
258: * @exception CertificateException on decoding errors.
259: */
260: public void decode(InputStream in) throws CertificateException {
261: throw new CertificateException(
262: "Method not to be called directly.");
263: }
264:
265: /**
266: * Set the attribute value.
267: * @exception CertificateException on attribute handling errors.
268: */
269: public void set(String name, Object obj)
270: throws CertificateException, IOException {
271: if (!(obj instanceof Date)) {
272: throw new CertificateException(
273: "Attribute must be of type Date.");
274: }
275: if (name.equalsIgnoreCase(NOT_BEFORE)) {
276: notBefore = (Date) obj;
277: } else if (name.equalsIgnoreCase(NOT_AFTER)) {
278: notAfter = (Date) obj;
279: } else {
280: throw new CertificateException(
281: "Attribute name not recognized by"
282: + " CertAttrSet:PrivateKeyUsage.");
283: }
284: encodeThis();
285: }
286:
287: /**
288: * Get the attribute value.
289: * @exception CertificateException on attribute handling errors.
290: */
291: public Object get(String name) throws CertificateException {
292: if (name.equalsIgnoreCase(NOT_BEFORE)) {
293: return (new Date(notBefore.getTime()));
294: } else if (name.equalsIgnoreCase(NOT_AFTER)) {
295: return (new Date(notAfter.getTime()));
296: } else {
297: throw new CertificateException(
298: "Attribute name not recognized by"
299: + " CertAttrSet:PrivateKeyUsage.");
300: }
301: }
302:
303: /**
304: * Delete the attribute value.
305: * @exception CertificateException on attribute handling errors.
306: */
307: public void delete(String name) throws CertificateException,
308: IOException {
309: if (name.equalsIgnoreCase(NOT_BEFORE)) {
310: notBefore = null;
311: } else if (name.equalsIgnoreCase(NOT_AFTER)) {
312: notAfter = null;
313: } else {
314: throw new CertificateException(
315: "Attribute name not recognized by"
316: + " CertAttrSet:PrivateKeyUsage.");
317: }
318: encodeThis();
319: }
320:
321: /**
322: * Return an enumeration of names of attributes existing within this
323: * attribute.
324: */
325: public Enumeration getElements() {
326: AttributeNameEnumeration elements = new AttributeNameEnumeration();
327: elements.addElement(NOT_BEFORE);
328: elements.addElement(NOT_AFTER);
329:
330: return (elements.elements());
331: }
332:
333: /**
334: * Return the name of this attribute.
335: */
336: public String getName() {
337: return (NAME);
338: }
339: }
|