CertificateValidity.java revision 51b1b6997fd3f980076b8081f7f1165ccc2a4008
1/*
2 * Copyright (c) 1997, 2006, 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 */
25package sun.security.x509;
26
27import java.io.IOException;
28import java.io.OutputStream;
29import java.security.cert.*;
30import java.util.Date;
31import java.util.Enumeration;
32
33import sun.security.util.*;
34
35/**
36 * This class defines the interval for which the certificate is valid.
37 *
38 * @author Amit Kapoor
39 * @author Hemma Prafullchandra
40 * @see CertAttrSet
41 */
42public class CertificateValidity implements CertAttrSet<String> {
43    /**
44     * Identifier for this attribute, to be used with the
45     * get, set, delete methods of Certificate, x509 type.
46     */
47    public static final String IDENT = "x509.info.validity";
48    /**
49     * Sub attributes name for this CertAttrSet.
50     */
51    public static final String NAME = "validity";
52    public static final String NOT_BEFORE = "notBefore";
53    public static final String NOT_AFTER = "notAfter";
54    private static final long YR_2050 = 2524636800000L;
55
56    // Private data members
57    private Date        notBefore;
58    private Date        notAfter;
59
60    // Returns the first time the certificate is valid.
61    private Date getNotBefore() {
62        return (new Date(notBefore.getTime()));
63    }
64
65    // Returns the last time the certificate is valid.
66    private Date getNotAfter() {
67       return (new Date(notAfter.getTime()));
68    }
69
70    // Construct the class from the DerValue
71    private void construct(DerValue derVal) throws IOException {
72        if (derVal.tag != DerValue.tag_Sequence) {
73            throw new IOException("Invalid encoded CertificateValidity, " +
74                                  "starting sequence tag missing.");
75        }
76        // check if UTCTime encoded or GeneralizedTime
77        if (derVal.data.available() == 0)
78            throw new IOException("No data encoded for CertificateValidity");
79
80        DerInputStream derIn = new DerInputStream(derVal.toByteArray());
81        DerValue[] seq = derIn.getSequence(2);
82        if (seq.length != 2)
83            throw new IOException("Invalid encoding for CertificateValidity");
84
85        if (seq[0].tag == DerValue.tag_UtcTime) {
86            notBefore = derVal.data.getUTCTime();
87        } else if (seq[0].tag == DerValue.tag_GeneralizedTime) {
88            notBefore = derVal.data.getGeneralizedTime();
89        } else {
90            throw new IOException("Invalid encoding for CertificateValidity");
91        }
92
93        if (seq[1].tag == DerValue.tag_UtcTime) {
94            notAfter = derVal.data.getUTCTime();
95        } else if (seq[1].tag == DerValue.tag_GeneralizedTime) {
96            notAfter = derVal.data.getGeneralizedTime();
97        } else {
98            throw new IOException("Invalid encoding for CertificateValidity");
99        }
100    }
101
102    /**
103     * Default constructor for the class.
104     */
105    public CertificateValidity() { }
106
107    /**
108     * The default constructor for this class for the specified interval.
109     *
110     * @param notBefore the date and time before which the certificate
111     *                   is not valid.
112     * @param notAfter the date and time after which the certificate is
113     *                  not valid.
114     */
115    public CertificateValidity(Date notBefore, Date notAfter) {
116        this.notBefore = notBefore;
117        this.notAfter = notAfter;
118    }
119
120    /**
121     * Create the object, decoding the values from the passed DER stream.
122     *
123     * @param in the DerInputStream to read the CertificateValidity from.
124     * @exception IOException on decoding errors.
125     */
126    public CertificateValidity(DerInputStream in) throws IOException {
127        DerValue derVal = in.getDerValue();
128        construct(derVal);
129    }
130
131    /**
132     * Return the validity period as user readable string.
133     */
134    public String toString() {
135        if (notBefore == null || notAfter == null)
136            return "";
137        return ("Validity: [From: " + notBefore.toString() +
138             ",\n               To: " + notAfter.toString() + "]");
139    }
140
141    /**
142     * Encode the CertificateValidity period in DER form to the stream.
143     *
144     * @param out the OutputStream to marshal the contents to.
145     * @exception IOException on errors.
146     */
147    public void encode(OutputStream out) throws IOException {
148
149        // in cases where default constructor is used check for
150        // null values
151        if (notBefore == null || notAfter == null) {
152            throw new IOException("CertAttrSet:CertificateValidity:" +
153                                  " null values to encode.\n");
154        }
155        DerOutputStream pair = new DerOutputStream();
156
157        if (notBefore.getTime() < YR_2050) {
158            pair.putUTCTime(notBefore);
159        } else
160            pair.putGeneralizedTime(notBefore);
161
162        if (notAfter.getTime() < YR_2050) {
163            pair.putUTCTime(notAfter);
164        } else {
165            pair.putGeneralizedTime(notAfter);
166        }
167        DerOutputStream seq = new DerOutputStream();
168        seq.write(DerValue.tag_Sequence, pair);
169
170        out.write(seq.toByteArray());
171    }
172
173    /**
174     * Set the attribute value.
175     */
176    public void set(String name, Object obj) throws IOException {
177        if (!(obj instanceof Date)) {
178            throw new IOException("Attribute must be of type Date.");
179        }
180        if (name.equalsIgnoreCase(NOT_BEFORE)) {
181            notBefore = (Date)obj;
182        } else if (name.equalsIgnoreCase(NOT_AFTER)) {
183            notAfter = (Date)obj;
184        } else {
185            throw new IOException("Attribute name not recognized by " +
186                            "CertAttrSet: CertificateValidity.");
187        }
188    }
189
190    /**
191     * Get the attribute value.
192     */
193    public Object get(String name) throws IOException {
194        if (name.equalsIgnoreCase(NOT_BEFORE)) {
195            return (getNotBefore());
196        } else if (name.equalsIgnoreCase(NOT_AFTER)) {
197            return (getNotAfter());
198        } else {
199            throw new IOException("Attribute name not recognized by " +
200                            "CertAttrSet: CertificateValidity.");
201        }
202    }
203
204    /**
205     * Delete the attribute value.
206     */
207    public void delete(String name) throws IOException {
208        if (name.equalsIgnoreCase(NOT_BEFORE)) {
209            notBefore = null;
210        } else if (name.equalsIgnoreCase(NOT_AFTER)) {
211            notAfter = null;
212        } else {
213            throw new IOException("Attribute name not recognized by " +
214                            "CertAttrSet: CertificateValidity.");
215        }
216    }
217
218    /**
219     * Return an enumeration of names of attributes existing within this
220     * attribute.
221     */
222    public Enumeration<String> getElements() {
223        AttributeNameEnumeration elements = new AttributeNameEnumeration();
224        elements.addElement(NOT_BEFORE);
225        elements.addElement(NOT_AFTER);
226
227        return (elements.elements());
228    }
229
230    /**
231     * Return the name of this attribute.
232     */
233    public String getName() {
234        return (NAME);
235    }
236
237    /**
238     * Verify that the current time is within the validity period.
239     *
240     * @exception CertificateExpiredException if the certificate has expired.
241     * @exception CertificateNotYetValidException if the certificate is not
242     * yet valid.
243     */
244    public void valid()
245    throws CertificateNotYetValidException, CertificateExpiredException {
246        Date now = new Date();
247        valid(now);
248    }
249
250    /**
251     * Verify that the passed time is within the validity period.
252     * @param now the Date against which to compare the validity
253     * period.
254     *
255     * @exception CertificateExpiredException if the certificate has expired
256     * with respect to the <code>Date</code> supplied.
257     * @exception CertificateNotYetValidException if the certificate is not
258     * yet valid with respect to the <code>Date</code> supplied.
259     *
260     */
261    public void valid(Date now)
262    throws CertificateNotYetValidException, CertificateExpiredException {
263        /*
264         * we use the internal Dates rather than the passed in Date
265         * because someone could override the Date methods after()
266         * and before() to do something entirely different.
267         */
268        if (notBefore.after(now)) {
269            throw new CertificateNotYetValidException("NotBefore: " +
270                                                      notBefore.toString());
271        }
272        if (notAfter.before(now)) {
273            throw new CertificateExpiredException("NotAfter: " +
274                                                  notAfter.toString());
275        }
276    }
277}
278