View Javadoc
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 }