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