Home | History | Annotate | Download | only in x509
      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